Boost.Beast WebSocket如何让async_read排队避免io_context.run提前退出
Boost.Beast WebSocket客户端ioc.run()提前退出问题解决方案
基础方案:正确实现循环读逻辑(覆盖你提到的两点要求)
你遇到的核心问题是异步任务提交的时间间隙导致io_context误判无待办任务,按以下方式落地官方给出的两点方案即可覆盖基础逻辑:
- 封装独立的
do_read()函数统一发起读请求,避免重复代码 - 在
on_read()末尾和握手成功回调中都调用do_read(),保证读请求持续排入io_context
对应实现代码如下:
// 类成员函数:独立封装的读请求发起入口 void session::do_read() { io_in_progress_ = true; ws_.async_read( buffer_, std::bind( &session::on_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2 ) ); } // 读回调逻辑 void session::on_read(boost::system::error_code ec, std::size_t bytes_transferred) { io_in_progress_ = false; boost::ignore_unused(bytes_transferred); if(ec) return fail(ec, "read"); std::cout << "on_read callback : " << boost::beast::buffers(buffer_.data()) << std::endl; // 清空缓冲区准备下一次读 buffer_.consume(buffer_.size()); // 末尾调用do_read发起下一轮读,保证任务连续 do_read(); } // 握手成功回调中首次调用do_read启动读循环 void session::on_handshake(boost::system::error_code ec) { if(ec) return fail(ec, "handshake"); // 启动首次读 do_read(); // 若有初始写入需求可在此处发起async_write }
Boost 1.70+ 版本优化方案(@sehe提到的executor方案落地)
如果已经升级到Boost 1.70及以上版本,可通过加执行器工作守卫彻底解决间隙退出问题:
// 类成员变量声明 boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work_guard_; // 构造函数中初始化守卫,绑定io_context session::session(boost::asio::io_context& ioc) : work_guard_(boost::asio::make_work_guard(ioc)) // 其他成员初始化逻辑 {} // 确定要关闭连接时手动释放守卫,允许io_context正常退出 void session::close() { ws_.async_close(boost::beast::websocket::close_code::normal, [self = shared_from_this()](boost::system::error_code ec) { self->work_guard_.reset(); }); }
Boost 1.67 兼容解决方案
1.67版本没有executor_work_guard,可使用旧版io_context::work实现相同的守卫效果:
// 类成员变量声明 std::unique_ptr<boost::asio::io_context::work> work_; // 构造函数中初始化work对象 session::session(boost::asio::io_context& ioc) : work_(std::make_unique<boost::asio::io_context::work>(ioc)) // 其他成员初始化逻辑 {} // 关闭连接时释放work对象,允许io_context退出 void session::close() { ws_.async_close(boost::beast::websocket::close_code::normal, [self = shared_from_this()](boost::system::error_code ec) { self->work_.reset(); }); }
内容的提问来源于stack exchange,提问作者mqmarathon
相关产品推荐
相关产品推荐

