不推荐新项目使用websocketpp,因其基于C++11和Boost.Asio,存在连接生命周期与消息处理耦合、无弱引用机制、同步DNS阻塞线程等设计缺陷,易导致dangling指针、event loop饥饿及静默失败等问题。

websocketpp 为什么现在不推荐新项目用
websocketpp 是 C++11 时代较早的 WebSocket 库,基于 Boost.Asio,但它的设计导致很多现代项目踩坑。最直接的问题是:它把连接生命周期和消息处理耦合在 connection_ptr 上,一旦连接断开,connection_ptr 可能变 dangling,而库本身不提供安全的弱引用机制;另外,它默认启用同步 DNS 解析,在高并发客户端场景下会阻塞线程。
实操建议:
- 仅在已有老项目维护、且无法升级编译器或依赖时继续用;
- 若必须用,务必禁用
set_reuse_addr(true)后再调用listen(),否则 Linux 下频繁重启服务会报Address already in use; - 不要在
on_message回调里做耗时操作(比如文件写入),它运行在 Asio 的 I/O 线程上,会拖慢整个 event loop; - 发送消息前检查
get_state() == websocketpp::session::state::open,否则可能静默失败——它不会抛异常,只记录日志到errorchannel。
uWebSockets 的 C++ 绑定怎么正确链接
uWebSockets(注意不是 uWS)已归档,当前活跃分支是 uWS(即 uWebSockets.js 的 C++ 原生实现),官方明确要求使用 C++20 且只支持 Linux/macOS。它的构建方式和传统 CMake 项目不同:不生成 .a/.so,而是通过 add_subdirectory() 直接内联源码。
常见错误现象:undefined reference to uWS::App::run() 或 uWS::SSLApp undefined —— 这是因为没正确定义宏或链接 OpenSSL。
实操建议:
- 在
CMakeLists.txt中必须先设置set(CMAKE_CXX_STANDARD 20),再add_subdirectory(uWebSockets); - 若用 TLS,需定义
-DUWS_WITH_OPENSSL=ON,并确保系统有libssl-dev(Ubuntu)或openssl-devel(CentOS),否则编译会跳过 SSL 支持,uWS::SSLApp类不可用; - 不要手动
target_link_libraries(your_target uWS),它内部已处理依赖;但需确保你的 target 也用了set_property(TARGET your_target PROPERTY CXX_STANDARD 20); - 接收二进制消息时,用
ws->getBuffer()拿原始指针,别用std::string构造——它会额外拷贝,且不保证 null-terminated。
如何在 uWS 中安全地跨线程发消息
uWS 的 event loop 是单线程的,所有回调(onMessage、onOpen)都在同一个线程执行。如果你从其他线程(比如数据库线程池)调用 ws->send(),会触发未定义行为,大概率 crash 或静默丢消息。
实操建议:
- 用
app->publish()+ 自定义 topic 做进程内广播,比手动管理连接列表更安全; - 若必须点对点发送,走
us_loop_post()把任务投递回主线程:在你的 worker 线程中调用us_loop_post(us_socket_context_get_loop(ssl ? sslContext : httpContext), [](struct us_loop_t *) { /* send here */ });; - 避免在
onClose回调里调用ws->close()—— 它已被关闭,再调用会 double-free; - 如果要用异步写,优先考虑
ws->write()而非send(),前者不等待 flush,适合流式推送(如日志 tail)。
websocketpp 和 uWS 的错误日志怎么看
两者都不输出到 std::cout,默认全走内部 logger,但配置方式完全不同。不设好就等于“出错了但不知道错在哪”。
websocketpp 的日志开关靠模板参数:websocketpp::config::asio_tls::core 默认只开 websocketpp::log::elevel::warn,连连接建立都不打。要看到握手细节,得继承并重写 get_alog() 和 get_elog() 返回自定义 logger。
uWS 则简单粗暴:定义 -DUWS_LOG_LEVEL=3(3 = INFO)即可输出关键事件,但要注意它只在 debug build 生效;release 下即使定义也无输出。
实操建议:
- websocketpp 中,把
set_access_channels(websocketpp::log::alevel::all)和clear_access_channels(websocketpp::log::alevel::frame_payload)配合用,既看到关键流程又避免刷屏; - uWS 日志没有异步缓冲,高频率
send()下日志本身会成为瓶颈,上线前务必关掉(不定义UWS_LOG_LEVEL); - 两者都建议重定向日志到文件:websocketpp 用
std::ofstream包装的ostream;uWS 没开放接口,只能改源码里的fprintf(stderr, ...)行——但这违反语义,不如用dup2()在启动时把 stderr 重定向。
真正难的不是选库,是理解它们各自对线程模型、内存生命周期和错误传播的隐含假设。哪怕只用一个 send(),背后也可能藏着 DNS 阻塞、SSL 握手超时、buffer 拷贝、event loop 饥饿这些点。没暴露错误,不代表没问题。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











