WebSocket 在 C ++ 中无标准库支持,websocketpp 是主流纯头文件方案;需正确配置 Boost.Asio 依赖、禁用 permessage-deflate 压缩、处理连接生命周期事件,并注意线程安全与广播机制。

WebSocket 在 C++ 中没有 标准库 支持,websocketpp 是目前最成熟、免依赖 Boost.Asio(可选)、纯头文件的主流方案。它不绑定具体网络 后端,但默认推荐搭配 Boost.Asio 使用;若想零依赖,也可用 standalone Asio 替代,但需手动处理 TLS 和底层 socket 细节。
如何配置 websocketpp(CMake + Boost.Asio)
常见错误是只包含头文件却未链接 Boost.System 或漏定义宏,导致编译失败或运行时崩溃。
- 确保安装了
boost(≥1.65),至少包含boost_system和boost_thread - CMakeLists.txt 中必须添加:
find_package(Boost REQUIRED COMPONENTS system thread) target_link_libraries(your_target PRIVATE Boost::system Boost::thread) - 在包含
websocketpp/config/asio_no_tls.hpp前,定义BOOST_ASIO_STANDALONE会导致冲突,应避免;正确做法是直接使用asio.hpp或asio_no_tls.hpp,并确保BOOST_SYSTEM_DYN_LINK宏与链接方式一致 - 若用 MinGW 编译,需额外加
-DBOOST_THREAD_USE_LIB防止 undefined reference to `boost::system::generic_category()`
写一个最小可用的服务端(echo server)
核心是继承 websocketpp::server 模板,并注册消息回调。注意:所有 handler 回调都运行在 IO 线程中,不可阻塞;如需耗时操作,必须 offload 到线程池。
- 使用
websocketpp::config::asio(带 TLS 支持)或asio_no_tls(纯 HTTP 协议) -
set_message_handler的 lambda 参数是connection_hdl和message_ptr,后者需用get_payload()提取字符串 - 发送响应必须用
send(hdl, payload, opcode),其中opcode通常为websocketpp::frame::opcode::text - 服务端启动前必须调用
listen()和start_accept(),否则不会接收连接
#include #include #include typedef websocketpp::server server;
立即学习“C++ 免费学习笔记(深入)”;
int main() { server s; s.init_asio(); s.set_access_channels(websocketpp::log::alevel::all); s.clear_access_channels(websocketpp::log::alevel::frame_payload);
s.set_message_handler([](server* s, websocketpp::connection_hdl hdl, server::message_ptr msg) {std::string payload = msg->get_payload(); s->send(hdl, "echo:" + payload, websocketpp::frame::opcode::text); }); s.listen("0.0.0.0", "9002"); s.start_accept(); s.run();
}
如何处理连接生命周期与错误(on_open / on_close / on_fail)
实际项目中,仅处理消息远远不够。连接建立、异常中断、超时断开等事件必须显式捕获,否则会内存泄漏或状态错乱。
-
on_open中建议用s->get_con_from_hdl(hdl)获取连接对象,保存其 ID 或 IP 地址用于后续管理 -
on_close和on_fail都需检查ec(error_code):例如websocketpp::close::status::going_away表示正常关闭,而asio::error::operation_aborted多见于服务停止时的主动 cancel - 不要在
on_fail中调用s->close(hdl, ……)—— 此时连接已失效,会触发二次异常 - 若启用了 ping/pong(
set_pong_timeout),超时未响应会自动触发on_close,无需手动心跳检测
为什么 send() 后客户端收不到消息?
最常被忽略的是:websocketpp 默认启用 permessage-deflate 压缩(即使没协商成功),而某些 JS 客户端(如 浏览器 原生 WebSocket)不支持该扩展,导致静默丢包。
- 解决方法:初始化 server 后立即禁用压缩:
s.clear_access_channels(websocketpp::log::alevel::decompress_failure); s.set_permessage_deflate_enabled(false); - 另一个原因是异步发送未等待完成:若在
on_message中连续调用多次send(),且未检查返回的future(仅当启用asio::io_context::strand时才返回),可能因缓冲区满而丢弃后续消息 - 调试技巧:启用
websocketpp::log::alevel::frame_header查看每帧 opcode 和 length,确认是否真的发出了数据
真正麻烦的不是写通 echo,而是连接数增长后如何安全地广播、如何跨线程管理 connection_hdl、如何配合现有 event loop(比如 Qt 或 libuv)。这些地方 websocketpp 不提供银弹,得靠你自己加锁、引用计数或消息队列 —— 它只是个协议 栈,不是应用框架。






























