视频监控相关笔记
Qt编程指南,Qt新手教程,Qt Programming Guide
2024.12.16
json数据解析:

答案在这里:
C语言 | JSON格式天气数据的解析(附详细代码)_天气信息cjson格式-CSDN博客
2024.12.10
jason的数据拼接传输格式:

对应代码:
#include"cjason.h"
String WebVideoPlayWnd::PackageVideoMaskInfo()
{
QString info = "";
cJSON* json = cJSON_CreateObject();
cJSON_AddStringToObject(json, "deviceid", qstr2str(m_play_devid).c_str());
cJSON_AddNumberToObject(json, "windowID", (int)GetWndId());
cJSON_AddStringToObject(json, "cmdtype", qstr2str(m_videomask_name).c_str());
cJSON* funparam = cJSON_CreateObject();
cJSON_AddItemToObject(json, "funparam", funparam);
cJSON* vertex = cJSON_CreateArray();
cJSON_AddItemToObject(funparam, "vertex", vertex);
for (auto vm : m_video_mask_list) {
std::map<int, QPoint> vmpoints = vm->GetPoints();
if (vm->GetStyle() == VideoMaskStyle::VM_Line) {
cJSON* points = cJSON_CreateObject();
if (vmpoints.size() < 2) goto finish;
{ // beginvertex
cJSON* item = cJSON_CreateObject();
cJSON_AddNumberToObject(item, "x", vmpoints[0].x());
cJSON_AddNumberToObject(item, "y", vmpoints[0].y());
cJSON_AddItemToObject(points, "beginvertex", item);
}
{ // endvertex
cJSON* item = cJSON_CreateObject();
cJSON_AddNumberToObject(item, "x", vmpoints[1].x());
cJSON_AddNumberToObject(item, "y", vmpoints[1].y());
cJSON_AddItemToObject(points, "endvertex", item);
}
if (vmpoints.size() == 4) {
{ // centervertex
cJSON* item = cJSON_CreateObject();
cJSON_AddNumberToObject(item, "x", vmpoints[2].x());
cJSON_AddNumberToObject(item, "y", vmpoints[2].y());
cJSON_AddItemToObject(points, "centervertex", item);
}
{ // arrowvertex
cJSON* item = cJSON_CreateObject();
cJSON_AddNumberToObject(item, "x", vmpoints[3].x());
cJSON_AddNumberToObject(item, "y", vmpoints[3].y());
cJSON_AddItemToObject(points, "arrowvertex", item);
}
}
cJSON_AddItemToArray(vertex, points);
}
else if (vm->GetStyle() == VideoMaskStyle::VM_Polygon || vm->GetStyle() == VideoMaskStyle::VM_Rectangle) {
cJSON* pv = cJSON_CreateObject();
if (vm->GetDirection() != VideoMaskArrowDir::VMAD_NULL) {
cJSON_AddNumberToObject(pv, "dir", (int)vm->GetDirection());
}
cJSON* points = cJSON_CreateArray();
cJSON_AddItemToObject(pv, "roivertex", points);
for (auto ptmp : vmpoints) {
cJSON* point = cJSON_CreateArray();
cJSON* px = cJSON_CreateNumber(ptmp.second.x());
cJSON_AddItemToArray(point, px);
cJSON* py = cJSON_CreateNumber(ptmp.second.y());
cJSON_AddItemToArray(point, py);
cJSON_AddItemToArray(points, point);
}
cJSON_AddItemToArray(vertex, pv);
}
}
finish:
std::string body = cJSON_PrintUnformatted(json);
if(json) {
cJSON_Delete(json);
json = NULL;
}
body = unicodeToUtf8(str2qstr(body));
info = str2qstr(body);
return info;
}
附详细解释:


注意:{ } 括号 创建对象时生成。


注意:创建数组时,产生 [ ]
2024.12.02
音视频的RTSP的视频数据的回调函数:
void RtspPlayer::onMediaFrameCallback(
uint8_t* data, uint32_t datalen, // AV data and leng
MediaType media_type, CodecType codectype, // media type and codec type
uint64_t pts, // Pts
uint32_t sample_rate, // Audio - sample rate
uint32_t channels // Audio - channels
)
{
//DEBUG_LOG(INFO, "onMediaFrameCallback in 1 ! media_type = %d, datalen = %d\n", media_type, datalen);
if (m_status != PlayerStatus::PlayerStatus_Playing) return;
//DEBUG_LOG(INFO, "onMediaFrameCallback in 2! media_type = %d, datalen = %d\n", media_type, datalen);
int channle = 0;
if (media_type == MediaType::MEDIA_TYPE_VIDEO) {
m_videoframe_count++;
channle = 0;
RECORD_LOCK();
if (m_mp4muxer) {
m_mp4muxer->WriteVideoData(CodecType2RTCPCodecType(codectype), data, datalen, pts, 25);
}
}
else if (media_type == MediaType::MEDIA_TYPE_AUDIO) {
{
RECORD_LOCK();
if (m_mp4muxer) {
m_mp4muxer->WriteAudioData(CodecType2RTCPCodecType(codectype), data, datalen, pts);
}
}
if (!m_sound) return;
channle = 1;
}
if (m_window_id_change != m_window_id) {
if (m_decoder) {
m_decoder->ChangeDisplay(m_handle, m_direct_draw, m_catch, m_threshold);
m_decoder->ReSetWindowid(m_window_id);
m_window_id_change = m_window_id;
}
}
MediaFrameEX* frame = new MediaFrameEX(media_type, codectype);
frame->Write((uint8_t*)data, datalen);
frame->SetPts(pts);
frame->SetAudioChannel(channels);
frame->SetAudioSampleRate(sample_rate);
if (!m_pkts) {
delete frame;
frame = NULL;
return;
}
if (m_pkts->size() >= MAX_QUEUE_COUNT) {
DEBUG_LOG(ERROR, "MediaFrameEX queue is full!\n\n");
#if 0
MediaFrameEX* input_frame = m_pkts->dequeue();
delete input_frame;
input_frame = NULL;
#else
delete frame;
frame = NULL;
return;
#endif
}
m_pkts->enqueue(frame);
return;
}

2024.11.15
bug: QWidget页面布局 下方按钮的图例显示不完整
解决方法:MONITOR_CTROLAREA_H = 48, MONITOR_CTROLBUTTON_H = 40,按钮高度要稍小于容器高度。
QWidget* ctrol_wnd = new QWidget(this);
QHBoxLayout* ctrol_layout = new QHBoxLayout(ctrol_wnd);
ctrol_layout->setMargin(0);
ctrol_layout->setContentsMargins(QMargins(0, 0, 0, 0));
ctrol_layout->setSpacing(0);
ctrol_wnd->setLayout(ctrol_layout);
ctrol_wnd->setFixedHeight(MONITOR_CTROLAREA_H);
m_monitor_btn.reset(new QPushButton(this));
m_monitor_btn->setObjectName("CtrolMonitorBtn");
m_monitor_btn->setProperty("itemSelected", "select");//默认选中监视器
m_monitor_btn->setFixedHeight(MONITOR_CTROLBUTTON_H);
m_monitor_btn->setText(LanguageReader::GetInstance().GetLanguageText(SURVEILLANCE_FORM, "Monitor"));
2024.11.07
1.按钮图片添加:
qss 和 qrc 文件都需要修改;qrc:添加图片文件即可;qss 加载显示
2. 主界面添加子界面,子界面布局大小如何从主界面获取?
void SurveillanceWnd::InitUi()
{
{ // 总体布局
m_main_layout.reset(new QGridLayout(this));
// 设置水平间距
m_main_layout->setHorizontalSpacing(SMargin);
// 设置垂直间距
m_main_layout->setVerticalSpacing(SMargin);
// 设置组件间距
m_main_layout->setSpacing(SMargin);
m_main_layout->setContentsMargins(SMargin, SMargin, SMargin, SMargin);
for (int i = 0; i < 7; i++) m_main_layout->setRowStretch(i, 1);
for (int i = 0; i < 7; i++) m_main_layout->setColumnStretch(i, 1);
m_resouce_pannel.reset(new ResourceWnd(this));
m_view_pannel.reset(new QWidget(this));
m_view_pannel->setObjectName("SViewPannel");
m_alarm_pannel.reset(new QWidget(this));
m_alarm_pannel->setObjectName("SRAlarmPannel");
// 第0行,第0列开始,占1行1列
m_main_layout->addWidget(m_resouce_pannel.get(), 0, 0, 7, 1);
m_main_layout->addWidget(m_view_pannel.get(), 0, 1, 6, 6);
m_main_layout->addWidget(m_alarm_pannel.get(), 6, 1, 1, 6);
// 延迟执行 init_view_ui 直接调用不显示
QTimer::singleShot(0, this, &SurveillanceWnd::init_view_ui);
}
return;
}
void SurveillanceWnd::init_view_ui()
{
if (!m_view_wnd) {
m_view_wnd.reset(new ViewWnd(m_view_pannel->size(),m_view_pannel.get()));
}
}
注意:直接调用init_view_wnd,不生效,需要加延时
2024.10.21
1. 递归理解
https://zhuanlan.zhihu.com/p/88760014
2024.10.12
CEF在QT界面中镶嵌:
[02]Qt使用cef进行网页窗口的嵌入显示_linux +cef qt-CSDN博客
GitCode - 全球开发者的开源社区,开源代码托管平台 (源码)
Qt浏览器开发:关于CEF开发知识点以及QCef开发原理与使用-CSDN博客 (经典)
chrome 内核CEF 编译和qt 封装(下)_qt cef chrome-CSDN博客
Qt5.9.1结合CEF开发基于chorm的浏览器(二)_51CTO博客_基于chrome内核开发浏览器
第二个链接 文章很好


2024.10.11

2024.10.10
一、HTTP协议
http请求响应报文及session&cookie&token详解_token报文-CSDN博客
1.报文
2. cookie 与 session

3. 代码:POST 请求以及解析回复 内容,并获取licence 和 token

LoginErrorCode HTTPClientManager::GetToken(std::string username, std::string password, QString& message)
{
std::string login_str = "";
std::string url = "";
std::shared_ptr<NetworkClient> client;
HttpResponseData res;
// 获取秘钥 加密生成jason字符串
std::string key = get_key();
if (key.length() == 0) {
return LoginErrorCode::LoginErrorCode_NetWorkError;
}
{
std::string encrypted = encryptAndBase64(key.c_str(), password);
cJSON* login_json = cJSON_CreateObject();
cJSON_AddStringToObject(login_json, "username", username.c_str());
cJSON_AddStringToObject(login_json, "password", encrypted.c_str());
login_str = cJSON_PrintUnformatted(login_json);
if (login_json) {
cJSON_Delete(login_json);
login_json = NULL;
}
}
// Login
url = buildUrl(QueryCMD::QueryCMD_Login);
client.reset(new NetworkClient);
client->open();
res = client->POST(url, login_str);
DEBUG_LOG(INFO, "Login res, code = %d, body = %s\n", res.status_code, res.body.c_str());
switch (res.status_code) {
case HttpStatus::OK:
{
cJSON* json = cJSON_Parse(res.body.c_str());
if (json == NULL) {
const char* error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL) {
cJSON_Delete(json);
json = NULL;
DEBUG_LOG(ERROR, "Error before: %s\n", error_ptr);
return LoginErrorCode::LoginErrorCode_AuthFailed;
}
}
else {
cJSON* data = cJSON_GetObjectItem(json, "data");
if (data != NULL) {
cJSON* token = cJSON_GetObjectItem(data, "access_token");
if (!token) {
cJSON_Delete(json);
json = NULL;
return LoginErrorCode::LoginErrorCode_AuthFailed;
}
m_userinfo.m_token = token->valuestring;
token = cJSON_GetObjectItem(data, "expire_license");
if(token) {
m_userinfo.m_license_tip = GBKCharToUtf8String(token->valuestring);
}
}
cJSON_Delete(json);
json = NULL;
}
}
return LoginErrorCode::LoginErrorCode_Succ;
case HttpStatus::BadRequest: // 用户名错误
case HttpStatus::InternalServerError: // 密码错误
return LoginErrorCode::LoginErrorCode_NameOrPassError;
case HttpStatus::Forbidden:
return LoginErrorCode::LoginErrorCode_AuthFailed;
case HttpStatus::Conflict:
return LoginErrorCode::LoginErrorCode_LicenceExpire;
default:
return LoginErrorCode::LoginErrorCode_NetWorkError;
}
return LoginErrorCode::LoginErrorCode_Succ;
}


2024.10.09
1. 手动代码进行QT 界面布局
Qt入门教程【Core篇】Layout布局(布局管理器、手动布局)_qt layout-CSDN博客
Qt界面布局基础操作详解_qwidget 布局-CSDN博客

需要使用代码进行如上图所示进行布局:
// 创建主布局
QVBoxLayout* layout_main = new QVBoxLayout(this);
// 假设layout_title_bar是区域A的布局
layout_main->addLayout(layout_title_bar, 1); // 区域A的伸缩因子为1
// 创建日志列表布局,并添加到主布局中
QTableWidget* table_widget_log_list = new QTableWidget(0, 5); // 创建表格
table_widget_log_list->setHorizontalHeaderLabels({"时间", "用户名称", "日志类型", "日志内容", "操作"});
// 添加数据到表格 (这里省略了填充数据的部分)
// 将表格添加到主布局中,作为区域B
layout_main->addWidget(table_widget_log_list, 2); // 区域B的伸缩因子为2
// 设置对话框的布局
setLayout(layout_main);
QBoxLayout常用函数:
//添加一个带有缩放因子的layout void addLayout(QLayout *layout, int stretch = 0) //添加一个separatorItem void addSpacerItem(QSpacerItem *spacerItem) //将大小为size的不可拉伸空间(一个QSpacerItem)添加到此框布局的末尾。 //QBoxLayout提供默认的边距和间距。此功能增加了额外的空间。 void addSpacing(int size) //添加一个可拉伸空间 void addStretch(int stretch = 0) //将框限制为size大小 void addStrut(int size) //添加widget void addWidget(QWidget *widget, int stretch = 0, Qt::Alignment alignment = Qt::Alignment()) //获取方向 QBoxLayout::Direction direction() const //插入小部件相关 void insertItem(int index, QLayoutItem *item) void insertLayout(int index, QLayout *layout, int stretch = 0) void insertSpacerItem(int index, QSpacerItem *spacerItem) void insertSpacing(int index, int size) void insertStretch(int index, int stretch = 0) void insertWidget(int index, QWidget *widget, int stretch = 0, Qt::Alignment alignment = Qt::Alignment()) //设置方向 void setDirection(QBoxLayout::Direction direction) //设置拉伸因子相关 void setStretch(int index, int stretch) bool setStretchFactor(QWidget *widget, int stretch) bool setStretchFactor(QLayout *layout, int stretch) //获取拉伸因子 int stretch(int index) const
addLayout 与 addWidget有什么区别?
addLayout 和 addWidget 都是布局管理器中的方法,它们用于向布局中添加子元素,但两者的作用对象不同:
addWidget(QWidget *widget, int stretch = 0, Qt::Alignment alignment = Qt::Alignment())
这个方法用来将一个单独的 QWidget 添加到布局中。
第二个参数 stretch 是伸缩因子,它定义了控件在布局空间调整时如何扩展。默认值为 0,意味着该控件不会拉伸。
第三个参数 alignment 用于设置控件的对齐方式,默认情况下是按照布局本身的对齐规则。
addLayout(QLayout *layout, int stretch = 0)
这个方法用来将另一个 QLayout(如 QVBoxLayout, QHBoxLayout 等)添加到当前布局中。
同样地,第二个参数 stretch 定义了这个子布局的伸缩因子。
当你想要创建复杂的布局结构,比如在一个垂直布局中嵌入一个水平布局时,就会使用这个方法。
简而言之:如果你想把一个具体的控件(例如按钮、标签等)添加到布局中,你应该使用 addWidget。
如果你想把一个已经包含了多个控件或其他布局的布局添加到另一个布局中,你应该使用 addLayout。
QGrideLayout 布局:
//添加Item
void addItem(QLayoutItem *item, int row, int column, int rowSpan = 1, int columnSpan = 1, Qt::Alignment alignment = Qt::Alignment())
//添加Layout
void addLayout(QLayout *layout, int row, int column, Qt::Alignment alignment = Qt::Alignment())
void addLayout(QLayout *layout, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment = Qt::Alignment())
//添加Widget
void addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment = Qt::Alignment())
void addWidget(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = Qt::Alignment())
//行和列的大小
QRect cellRect(int row, int column) const
//列个数
int columnCount() const
//列最小宽度
int columnMinimumWidth(int column) const
//列缩放因子
int columnStretch(int column) const
//通过索引获取item
void getItemPosition(int index, int *row, int *column, int *rowSpan, int *columnSpan) const
//水平间距
int horizontalSpacing() const
//获取第几行第几列的元素
QLayoutItem *itemAtPosition(int row, int column) const
//获取网格的原点角
Qt::Corner originCorner() const
//行数量
int rowCount() const
//行最小高度
int rowMinimumHeight(int row) const
//获取行的缩放因子
int rowStretch(int row) const
//设置列的最小宽度
void setColumnMinimumWidth(int column, int minSize)
//设置垂直的缩放因子
void setColumnStretch(int column, int stretch)
//设置水平间距
void setHorizontalSpacing(int spacing)
//将网格的原点角,即位置 (0, 0) 设置为角。
void setOriginCorner(Qt::Corner corner)
//设置某一行最小高度
void setRowMinimumHeight(int row, int minSize)
//设置行所占总行的比例
void setRowStretch(int row, int stretch)
//设置垂直间距
void setVerticalSpacing(int spacing)
//垂直间距
int verticalSpacing() const
void VerifyDialog::initUI() {
auto main_layout = new QGridLayout(); // 垂直布局
setLayout(main_layout);
write_apply_layout->addWidget(new QLabel("软件名称"), 0, 0); // 第 0 行 第 0 列
write_apply_layout->addWidget(new QLabel("--"), 0, 1); // 第 0 行 第 1 列
write_apply_layout->addWidget(new QLabel("软件版本"), 0, 2); // 第 0 行 第 2 列
write_apply_layout->addWidget(new QLabel("--"), 0, 3); // 第 0 行 第 3 列
write_apply_layout->addWidget(new QLabel("申请日期"), 1, 0); // 第 1 行 第 0 列
write_apply_layout->addWidget(new QLabel("--"), 1, 1); // 第 1 行 第 1 列
write_apply_layout->addWidget(new QLabel("机械码"), 1, 2); // 第 1 行 第 2 列
write_apply_layout->addWidget(new QLabel("--"), 1, 3); // 第 1 行 第 3 列
}
2. 控件图片加载 从qss中
m_pic.reset(new QLabel(this));
QString StyleSheet = "LevelAWdg_";
StyleSheet += la_data.m_stylesheet_code;
setObjectName(StyleSheet);
StyleSheet = "LevelAWdgPic_";
StyleSheet += la_data.m_stylesheet_code;
m_pic->setObjectName(StyleSheet);
3. 动画淡出
m_animation.reset(new QPropertyAnimation(this, "windowOpacity"));
m_animation->setDuration(800);
m_animation->setStartValue(1);
m_animation->setEndValue(0);
connect(m_animation.get(), SIGNAL(finished()), this, SLOT(close()));
m_animation->start();
2024.08.30
一、QT 之 QTreeWidget 树形控件
Qt编程指南,Qt新手教程,Qt Programming Guide
一个树形结构的节点中的图表文本 、附带数据的添加:
QTreeWidgetItem* TourTreeWnd::InsertNode(NetNodeInfo node, QTreeWidgetItem* parent_item)
{
// 创建一个QVariant对象,用于存储NetNodeInfo类型的node
QVariant var;
var.setValue(node);
// 初始化一个指向QTreeWidgetItem的指针,用于存储新创建的节点
QTreeWidgetItem* Item = NULL;
// 检查parent_item是否为NULL,如果是,则表示要插入的节点是顶级节点
if (parent_item == NULL) {
// 为顶级节点创建一个新的QTreeWidgetItem对象
Item = new QTreeWidgetItem(m_tree.get());
// 设置新节点的第一个列的文本为node的Name属性
Item->setText(0, (QString)node.Name);
// 设置新节点的第一个列的工具提示与文本相同
Item->setToolTip(0, Item->text(0));
// 将新节点作为顶级节点添加到树形控件中
m_tree->addTopLevelItem(Item);
// 根据node的类型设置图标
// 如果节点类型是NodeType_TOURTASK,则使用特定类型的图标
if (node.Type == NodeType::NodeType_TOURTASK) {
Item->setIcon(0, QIcon(GetIconByNodetype(node.Type)));
}
// 注意:这里没有处理非NodeType_TOURTASK类型顶级节点的图标设置,可能是个遗漏
// 将QVariant对象var作为用户自定义数据存储在节点的第一个列上
Item->setData(0, Qt::UserRole, var);
// 设置节点第一个列的大小提示为30x30
Item->setSizeHint(0, QSize(30, 30));
}
// 如果parent_item不为NULL,则表示要插入的节点是子节点
else {
// 为子节点创建一个新的QTreeWidgetItem对象,并指定parent_item为其父节点
Item = new QTreeWidgetItem(parent_item);
// 设置子节点的大小提示为30x30
Item->setSizeHint(0, QSize(30, 30));
// 设置子节点的第一个列的文本为node的Name属性
Item->setText(0, (QString)node.Name);
// 设置子节点的第一个列的工具提示与文本相同
Item->setToolTip(0, Item->text(0));
// 根据node的类型或设备状态设置图标
// 如果节点类型是NodeType_DEVICE,则根据设备主类型、子类型和状态获取图标
if (node.Type == NodeType::NodeType_DEVICE) {
Item->setIcon(0, QIcon(GetIconByDevStatus(node.DevMainType, node.DevSubType, node.Status)));
}
// 如果不是NodeType_DEVICE类型,则根据节点类型获取图标
else {
Item->setIcon(0, QIcon(GetIconByNodetype(node.Type)));
}
// 将QVariant对象var作为用户自定义数据存储在节点的第一个列上
Item->setData(0, Qt::UserRole, var);
}
// 显示树形控件(通常不是必需的,因为可能在其他地方已经设置为可见)
m_tree->show();
// 展开树形控件中的所有节点,以便新插入的节点可见
m_tree->expandAll();
// 返回新创建的节点指针,以便调用者可以使用它
return Item;
}
其中注意以下几点:


二、视频播放
1. 主辅码流区别

2. RTSP
3. SDK的调用案例:
#pragma once
#include <memory>
#ifdef _WINDOWS
#include <Windows.h>
#ifdef LIBRTSPCLINET_SDK_EXPORTS
#define LIBRTSPCLINET_API __declspec(dllexport)
#else
#define LIBRTSPCLINET_API __declspec(dllimport)
#endif
#else
#define LIBRTSPCLINET_API
#endif
#include "Common.h"
using namespace std;
class LIBRTSPCLINET_API LibRtspClientManager
{
public:
static LibRtspClientManager& getInstance() {
static LibRtspClientManager instance;
return instance;
}
/* @ 初始化SDK:
@ 参数:
onLibRtspClientDateCB 数据回调函数地址
onLibRtspClientMsgCB 消息回调函数地址
@ 返回: bool
*/
bool Init();
/* @ 反初始化SDK:
@ 参数:
@ 返回: void
*/
void UnInit();
/* @ 创建RTSP Client:
@ 参数:
std::string url : rtsp url
TransProtocol trans_protocol : 0-udp, 1-tcp
int timeout : 超时时间,单位秒
@ 返回: int32_t rtsp session id
*/
uint32_t CreateRtspClient(std::string url,
std::string username, std::string password,
TransProtocol trans_protocol, RtspCallBack* callback, int timeout);
bool ReleaseRtspClient(uint32_t session_id);
/* @ 连接服务器
* @ 异步通知,rtsp连接情况在onLibRtspClientMsgCB反馈
*/
bool Connect(uint32_t session_id);
bool Play(uint32_t session_id, std::string params_json);
bool Control(uint32_t session_id, std::string params_json);
bool Pause(uint32_t session_id);
// 恢复播放
bool Resume(uint32_t session_id);
// 从指定位置恢复播放
bool Resume(uint32_t session_id, float npt);
bool Stop(uint32_t session_id);
void WaitForStop(uint32_t session_id);
private:
LibRtspClientManager();
virtual ~LibRtspClientManager();
class LibRtspClientPriv;
std::shared_ptr<LibRtspClientPriv> m_priv;
};
4. 一个webSocket第三方库;easywsclient.hpp easywsclient.cpp
Easywsclient: 强大且简单的C++ WebSocket客户端库-CSDN博客
下文代码摘自gitcode.com中:
#include "easywsclient.hpp"
//#include "easywsclient.cpp" // <-- include only if you don't want compile separately
#ifdef _WIN32
#pragma comment( lib, "ws2_32" )
#include <WinSock2.h>
#endif
#include <assert.h>
#include <stdio.h>
#include <string>
using easywsclient::WebSocket;
static WebSocket::pointer ws = NULL;
void handle_message(const std::string & message)
{
printf(">>> %s\n", message.c_str());
if (message == "world") { ws->close(); }
}
int main()
{
#ifdef _WIN32
INT rc;
WSADATA wsaData;
rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (rc) {
printf("WSAStartup Failed.\n");
return 1;
}
#endif
ws = WebSocket::from_url("ws://localhost:8126/foo");
assert(ws);
ws->send("goodbye");
ws->send("hello");
while (ws->getReadyState() != WebSocket::CLOSED) {
ws->poll();
ws->dispatch(handle_message);
}
delete ws;
#ifdef _WIN32
WSACleanup();
#endif
return 0;
}
更多推荐







所有评论(0)