最简 WebSocket 客户端需用 libwebsockets:先创建 context(port = CONTEXT_PORT_NO_LISTEN),再调 lws_client_connect_via_info() 建连,必须循环调用 lws_service() 驱动事件,所有逻辑通过回调处理,不可阻塞或忽略连接状态检查。

用 libwebsockets 实现最简 WebSocket 客户端
直接上手写 WebSocket 客户端,别碰裸 socket + 手撕握手 + 帧解析这套组合拳。C++ 没有标准 WebSocket 支持,libwebsockets 是目前最轻量、依赖少、纯 C 实现的靠谱选择——它不依赖 Boost,编译进项目也只多几百 KB。
关键点:它提供的是事件驱动模型,不是阻塞式 API;你得写回调函数处理连接、接收、关闭等事件,不能指望 send() 之后立刻收到回包。
常见错误现象:lws_client_connect_via_info() 返回 NULL 却没检查日志;连接成功但收不到消息,其实是没调用 lws_service() 主循环;或者把 lws_context 和 lws 对象生命周期搞混,提前释放了 context 导致 segfault。
- 安装时加
-DLWS_WITHOUT_TESTAPPS=ON -DLWS_WITHOUT_TEST_SERVER=ON省掉无关二进制 - 初始化
struct lws_context_creation_info必须设.port = CONTEXT_PORT_NO_LISTEN(客户端不用监听端口) - 连接前确保 DNS 可解析,
libwebsockets不自动重试失败的域名解析
on_ws_rx 回调里怎么安全读取文本消息
WebSocket 文本帧内容在 in 缓冲区里,但长度不等于 len —— 因为 libwebsockets 可能复用缓冲区,且 in 开头可能有协议头或分片残留。必须用 lws_get_frame_payload_length() 获取真实载荷长度,并确认 lws_is_first_fragment() 和 lws_is_last_fragment() 判断是否为完整消息。
典型误操作:直接 std::string(in, len) 构造字符串,结果拿到乱码或截断;或忽略 LWS_CALLBACK_RECEIVE 可能被多次调用(比如大消息被拆成多个帧)。
- 只在
lws_is_last_fragment()为 true 时才处理整条消息 - 用
lws_get_websocket_address()辅助调试,确认连的是预期地址 - 文本消息末尾不保证有
\0,别当 C 字符串用printf("%s", in)
发送消息前必须检查连接状态和缓冲区
lws_write() 不是“尽力而为”,它返回实际写入字节数,且只在连接就绪、发送队列有空间时才成功。如果返回值小于请求长度,说明底层缓冲区满或连接已断开——此时再调用会触发断言或静默失败。
容易被忽略的条件:发送前必须确认 lws_get_socket_fd(wsi) != -1 且 lws_wsi_state(wsi) == LRS_ESTABLISHED。否则 lws_write() 可能返回 -1 并设置 errno = ENOTCONN。
- 发文本用
LWS_WRITE_TEXT,发二进制用LWS_WRITE_BINARY,混用会触发协议错误 - 单次发送不要超过
lws_get_peer_write_allowance(wsi)返回值(需启用流量控制) - 想发完立刻 flush?不需要 ——
libwebsockets内部自动调度,手动调lws_callback_on_writable()反而可能打乱节奏
为什么 lws_service() 必须在主线程循环调用
libwebsockets 的事件循环不是后台线程,它不自己 spawn 线程。所有网络 I/O、定时器、回调都在你调用 lws_service() 时同步触发。跳过它,连接不会建立,消息不会发出,超时不会检测,回调永远不会执行。
新手常犯:启动连接后直接 sleep(5); return 0;,以为连接会后台完成——实际什么都没发生。或者在子线程里调 lws_service() 却没给该线程绑定 lws_context(context 默认线程安全,但 wsi 不是)。
- 推荐模式:
while (running) { lws_service(context, 0); },其中0表示非阻塞轮询 - 若需低延迟响应,可传毫秒数如
10,让函数最多等待 10ms 后返回 - 不要在回调里长时间阻塞(比如做文件 IO),否则整个事件循环卡住
真正麻烦的从来不是连上服务器,而是处理网络抖动下的重连逻辑、消息确认、心跳保活和缓冲区背压——这些得你自己补全,libwebsockets 只管协议层。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











