c++如何实现websocket通信_c++ websocketpp库配置与服务端逻辑【实战】

7次阅读

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

c++ 如何实现 websocket 通信_c++ websocketpp 库配置与服务端逻辑【实战】

WebSocket 在 C++ 中没有 标准库 支持,websocketpp 是目前最成熟、免依赖 Boost.Asio(可选)、纯头文件的主流方案。它不绑定具体网络 后端,但默认推荐搭配 Boost.Asio 使用;若想零依赖,也可用 standalone Asio 替代,但需手动处理 TLS 和底层 socket 细节。

如何配置 websocketpp(CMake + Boost.Asio)

常见错误是只包含头文件却未链接 Boost.System 或漏定义宏,导致编译失败或运行时崩溃。

  • 确保安装了 boost(≥1.65),至少包含 boost_systemboost_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.hppasio_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_hdlmessage_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_closeon_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 不提供银弹,得靠你自己加锁、引用计数或消息队列 —— 它只是个协议 ,不是应用框架。

text=ZqhQzanResources