C++ 实现Websocket(libwebsockets)

📅 2026/7/19 4:54:06
C++ 实现Websocket(libwebsockets)
LibwebsocketsLWS是一个灵活、轻量级的纯C库使用非阻塞事件循环以极小的占用空间轻松实现现代网络协议。自2010年以来它一直在不断开发并被全球数千万台设备和数千名开发人员使用。uWebSockets 安装需要先看《VCPKG 跨平台C 库管理器》安装VCPKG环境之后再来进行安装这个需要VCKPKG C库管理工具。通过命令安装vcpkg install libwebsockets安装完毕然后就可以直接引用并使用了。示例服务端#include libwebsockets.h #include string.h #include signal.h #include stdio.h #define MAX_PAYLOAD_SIZE 1024 static int interrupted 0; // 每个连接的私有数据结构Per-Session Data struct per_session_data__echo { unsigned char buf[LWS_PRE MAX_PAYLOAD_SIZE]; size_t len; }; // 信号处理 static void sigint_handler(int sig) { interrupted 1; } // 服务器回调函数 static int callback_echo(struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len) { struct per_session_data__echo* pss (struct per_session_data__echo*)user; switch (reason) { case LWS_CALLBACK_RECEIVE: if (len MAX_PAYLOAD_SIZE) len MAX_PAYLOAD_SIZE; // 复制接收到的数据注意要偏移 LWS_PRE 长度 memcpy(pss-buf[LWS_PRE], in, len); pss-len len; // 标记该连接可写通知底层触发 WRITEABLE 回调 lws_callback_on_writable(wsi); break; case LWS_CALLBACK_SERVER_WRITEABLE: if (pss-len 0) { // 发送数据指针必须指向预留了 LWS_PRE 后的位置 int n lws_write(wsi, pss-buf[LWS_PRE], pss-len, LWS_WRITE_TEXT); if (n 0) return -1; pss-len 0; // 清空标志防止重复发送 } break; default: break; } return 0; } // 协议列表 static struct lws_protocols protocols[] { { echo-protocol, callback_echo, sizeof(struct per_session_data__echo), MAX_PAYLOAD_SIZE, 0, NULL, 0 }, { NULL, NULL, 0, 0, 0, NULL, 0 } /* 结束标志 */ }; int main(void) { struct lws_context_creation_info info; struct lws_context* context; int n 0; signal(SIGINT, sigint_handler); memset(info, 0, sizeof(info)); info.port 8081; // 监听端口 info.protocols protocols; // 绑定的协议 info.gid -1; info.uid -1; context lws_create_context(info); if (!context) { lwsl_err(lws init failed\n); return 1; } printf(Echo 服务器已启动正在监听 8081 端口...\n); // 事件循环 while (n 0 !interrupted) { n lws_service(context, 0); } lws_context_destroy(context); printf(服务器已退出\n); return 0; }客户端#include libwebsockets.h #include string.h #include signal.h #include stdio.h static int interrupted 0; static int client_finished 0; // 客户端回调函数 static int callback_client_echo(struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len) { switch (reason) { case LWS_CALLBACK_CLIENT_ESTABLISHED: printf(客户端连接服务器成功\n); // 连接成功后请求写权限以发送第一条数据 lws_callback_on_writable(wsi); break; case LWS_CALLBACK_CLIENT_WRITEABLE: { const char* msg Hello Libwebsockets Echo!; size_t msg_len strlen(msg); unsigned char buf[LWS_PRE 128]; // 必须在 LWS_PRE 之后填入数据 memcpy(buf[LWS_PRE], msg, msg_len); printf(客户端发送消息 - \%s\\n, msg); lws_write(wsi, buf[LWS_PRE], msg_len, LWS_WRITE_TEXT); break; } case LWS_CALLBACK_CLIENT_RECEIVE: // 打印收到的回显数据 printf(客户端收到回显 - \%.*s\\n, (int)len, (char*)in); client_finished 1; // 标记完成准备退出循环 interrupted 1; break; case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: lwsl_err(客户端连接失败\n); interrupted 1; break; default: break; } return 0; } static struct lws_protocols protocols[] { { echo-protocol, callback_client_echo, 0, 1024, 0, NULL, 0 }, { NULL, NULL, 0, 0, 0, NULL, 0 } }; int main(void) { struct lws_context_creation_info info; struct lws_client_connect_info i; struct lws_context* context; int n 0; memset(info, 0, sizeof(info)); info.port CONTEXT_PORT_NO_LISTEN; // 客户端不需要监听端口 info.protocols protocols; context lws_create_context(info); if (!context) { lwsl_err(lws context init failed\n); return 1; } // 配置连接参数 memset(i, 0, sizeof(i)); i.context context; i.address 127.0.0.1; // 服务器 IP i.port 8081; // 服务器端口 i.path /; i.host i.address; i.origin i.address; i.protocol echo-protocol; // 必须与服务器的协议名一致 i.ssl_connection 0; // 0 表示不使用 SSL (ws://) if (!lws_client_connect_via_info(i)) { lwsl_err(Client connection failed\n); lws_context_destroy(context); return 1; } // 事件循环 while (n 0 !interrupted) { n lws_service(context, 0); } lws_context_destroy(context); return 0; }调试结果先启动服务端再启动客户端再启动客户端可见我们已经实现了WebSocket Server和 WebSocket Client。