用 C++ 快速搭建 WebSocket 服务及踩坑记录
用 C++ 快速搭建 WebSocket 服务及踩坑记录
做实时数据交互(比如设备监控、即时通知)时,HTTP 轮询总绕不开两个问题:延迟高、浪费服务器资源。而 WebSocket 的长连接特性,能让前后端主动互发数据,刚好解决这些痛点。
如果你的项目后端是 C++ 技术栈,用 WebSocketpp 库搭 WebSocket 服务很合适 —— 轻量、不用切换语言,还能直接对接现有业务逻辑。这篇就从环境搭建到前后端联调,一步步讲清楚怎么实现,顺便避避常见的坑。
一、先搞懂:为什么选 WebSocket 而非 HTTP 轮询?
HTTP 轮询是 “客户端问、服务器答”,哪怕没新数据,也要频繁发请求,不仅延迟能到几秒,还会占用额外带宽。而 WebSocket 一旦握手成功,就是双向长连接:
-
服务器能主动推数据(比如设备状态更新后,立马传给前端);
-
没有多余 HTTP 头开销,延迟能压到 100ms 内;
-
不用频繁建立连接,省服务器资源。
二、环境搭建:Ubuntu 装 WebSocketpp 和 Boost
WebSocketpp 是头文件库,但依赖 Boost(主要用 asio 网络模块),直接用 apt 安装最省心:
# 装 Boost 核心库(asio 依赖)
sudo apt-get install libboost-dev libboost-system-dev
# 装 WebSocketpp
sudo apt-get install libwebsocketpp-dev
装完验证下:执行 ls /usr/include/websocketpp/
,能看到 connection.hpp
、endpoint_base.hpp
等文件,就说明装对了。
三、服务器端代码:C++ 实现核心逻辑
WebSocketpp 核心是 “事件驱动”,重点写连接、消息、断开的回调函数,再初始化启动服务器即可。
1. 定义基础类型
先指定配置(用不加密的 asio_no_tls
),简化后续代码:
#include <iostream>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>// 服务器类型
typedef websocketpp::server<websocketpp::config::asio> server_t;
// 消息指针类型
typedef server_t::message_ptr message_ptr;
2. 写回调函数
(1)连接建立:onOpen
连接成功时打日志,方便调试:
void onOpen(websocketpp::connection_hdl hdl) {std::cout << "✅ 新连接建立" << std::endl;
}
(2)连接断开:onClose
断开时清理日志:
void onClose(websocketpp::connection_hdl hdl) {std::cout << "❌ 连接断开" << std::endl;
}
(3)处理消息:onMessage(核心)
收到前端消息后,加后缀 “-Hello!” 回传(类似回声服务,实际项目可替换成业务逻辑):
void onMessage(server_t *server, websocketpp::connection_hdl hdl, message_ptr msg) {// 拿消息内容std::string body = msg->get_payload();std::cout << "📥 收到消息:" << body << std::endl;// 回消息auto conn = server->get_con_from_hdl(hdl);conn->send(body + "-Hello!", websocketpp::frame::opcode::value::text);std::cout << "📤 回传消息:" << body << "-Hello!" << std::endl;
}
3. 初始化并启动服务器(修复格式版)
按步骤初始化,绑定回调、设端口、启动服务,代码缩进和符号均为标准格式:
int main() {// 实例化服务器server_t server;// 关闭日志(调试时可改 websocketpp::log::alevel::all 打开)server.set_access_channels(websocketpp::log::alevel::none);// 初始化 asioserver.init_asio();// 绑定回调server.set_open_handler(onOpen);server.set_close_handler(onClose);auto msg_handler = std::bind(onMessage, &server, std::placeholders::_1, std::placeholders::_2);server.set_message_handler(msg_handler);// 启用地址重用(避免端口占用报错)server.set_reuse_addr(true);// 设端口、启动监听server.listen(8080);std::cout << "🚀 服务器启动,监听 ws://localhost:8080" << std::endl;// 接收连接、启动服务server.start_accept();server.run();return 0;
}
四、客户端代码:HTML+JS 快速测试
浏览器原生支持 WebSocket API,写个简单页面就能测:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>WebSocket 测试</title><style>body { padding: 20px; }#message { width: 300px; padding: 8px; }#submit { padding: 8px 16px; background: #4285f4; color: white; border: none; }</style>
</head>
<body><input type="text" id="message" placeholder="输入消息"><button id="submit">发送</button><script>// 连服务器(替换成你的服务器 IP)const websocket = new WebSocket("ws://192.168.195.128:8080");// 连接成功websocket.onopen = () => console.log("✅ 客户端连成功");// 收消息websocket.onmessage = (e) => console.log("📥 收服务端消息:", e.data);// 出错websocket.onerror = () => console.error("❌ 连接异常");// 断开websocket.onclose = () => console.log("❌ 连接关闭");// 点击发送const input = document.querySelector("#message");const btn = document.querySelector("#submit");btn.onclick = () => {const msg = input.value.trim();if (msg) {websocket.send(msg);console.log("📤 发消息:", msg);input.value = "";}};</script>
</body>
</html>
五、联调测试:一步到位跑通
1. 编译服务器代码
WebSocketpp 依赖 Boost 和线程库,编译时要加参数:
# 假设代码存为 ws_server.cpp
g++ -o ws_server ws_server.cpp -lboost_system -pthread
2. 启动服务器
./ws_server
看到 “🚀 服务器启动,监听 ws://localhost:8080”,就是成功了。
3. 测试客户端
-
用浏览器打开 HTML 文件,按 F12 开控制台;
-
输入消息(比如 “Hi”),点 “发送”;
-
看两端日志:
-
服务器:
✅ 新连接建立
→📥 收到消息:Hi
→📤 回传消息:Hi-Hello!
; -
客户端:
✅ 客户端连成功
→📤 发消息:Hi
→📥 收服务端消息:Hi-Hello!
。
这样就说明联调通了!
六、踩坑记录:避坑指南
-
编译报错 “undefined reference”:没加
-lboost_system
或-pthread
,补全参数即可; -
客户端连不上:检查服务器 IP 是不是写对(比如虚拟机里的服务器,不能用 localhost);
-
端口占用:用
netstat -tuln | grep 8080
查占用进程,kill 后重启; -
日志太乱:默认日志多,用
set_access_channels(websocketpp::log::alevel::none)
关掉。
总结
用 WebSocketpp 搭 C++ WebSocket 服务,不用自己解析协议,核心就是写回调和初始化。适合 C++ 技术栈的实时场景,轻量又好整合现有业务。按上面的步骤走,基本能避开大部分坑,快速跑通功能。