如何基于boost::beast维持WebSocket长连接?
解决Boost.Beast WebSocket异步客户端自动断开的问题
我明白你遇到的困扰——就算移除了on_read里的关闭代码,连接还是会在单次读取完成后断开,而且io_context也跟着退出了。这其实是因为示例里的session对象在on_read结束后没有绑定新的异步操作,导致它的shared_ptr引用计数降到0,对象被销毁,WebSocket连接自然就断了,同时io_context因为没有待处理的任务,直接停止运行。
核心原因拆解
Boost.Beast的异步模型依赖std::shared_ptr管理session的生命周期:当最后一个绑定到session的异步操作完成后,如果没有新的异步任务启动,shared_ptr的引用计数会归零,session被销毁,连接也就跟着关闭了。而io_context.run()本身就是在所有任务完成后自动退出的。
具体解决方案
要让连接持续保持,且io_context一直运行到你显式关闭,需要做两件关键的事:
1. 在on_read完成后,再次发起异步读操作
这会形成一个持续的读取循环,维持session的生命周期,让连接一直活跃。修改你的on_read函数:
void on_read(boost::system::error_code ec, std::size_t bytes_transferred) { boost::ignore_unused(bytes_transferred); if(ec) return fail(ec, "read"); // 处理收到的消息(比如打印、业务逻辑处理) std::cout << boost::beast::buffers_to_string(buffer_.data()) << std::endl; buffer_.consume(buffer_.size()); // 关键:再次发起异步读,维持读取循环 ws_.async_read( buffer_, std::bind( &session::on_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); }
2. 添加显式关闭的机制
你需要一个主动关闭连接并停止io_context的方式。可以给session类新增一个close方法,主动发起WebSocket关闭流程:
class session : public std::enable_shared_from_this<session> { // ... 已有成员变量 ... boost::asio::io_context& ios_; // 持有io_context的引用 public: // 构造函数中传入io_context引用 session(boost::asio::io_context& ios) : ios_(ios), ws_(ios) {} void close() { // 发起异步关闭操作 ws_.async_close( boost::beast::websocket::close_code::normal, std::bind( &session::on_close, shared_from_this(), std::placeholders::_1)); } private: void on_close(boost::system::error_code ec) { if(ec) return fail(ec, "close"); // 关闭底层套接字,并停止io_context ws_.next_layer().close(); ios_.stop(); } // ... 已有方法 ... };
3. 确保io_context持续运行
只要你的读取循环不中断,io_context就会一直处理异步读任务。当你需要关闭时,调用session::close(),on_close里的ios_.stop()会让ios.run()退出。
额外小贴士
- 可以给WebSocket设置心跳参数,避免长时间无数据被服务器主动断开:
ws_.set_option(boost::beast::websocket::stream_base::timeout::suggested(boost::beast::role_type::client)); - 如果需要同时处理多个连接或其他异步任务,
io_context可以一直运行,直到你主动调用stop()。
内容的提问来源于stack exchange,提问作者geeeek
相关产品推荐
相关产品推荐

