Boost.Asio Acceptor关闭重启异常:io_context.run()立即返回
问题:Boost Asio HTTP服务器重启后io_context::run()立即返回
问题背景
基于Boost官方单线程HTTP服务器示例修改,将地址解析、监听逻辑移至start_server(),停止逻辑移至end_server(),实现服务器启停功能。单次启停测试正常,但重启时调用io_context->run()会立即返回,服务器无法正常重启。
修改后的核心server_impl代码:
server_impl::server_impl( const std::string& address, const std::string& port, const std::shared_ptr<boost::asio::io_context>& io_context, const std::shared_ptr<connection_manager>& connection_manager, const std::shared_ptr<request_handler>& request_handler) : io_context_(io_context), acceptor_(*io_context_), connection_manager_(connection_manager), new_connection_(), request_handler_(request_handler), address_(address), port_(port) { } void server_impl::start_server() { boost::asio::ip::tcp::resolver resolver(*io_context_); boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(address_, port_).begin(); acceptor_.open(endpoint.protocol()); acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); acceptor_.bind(endpoint); acceptor_.listen(); start_accept(); } void server_impl::end_server() { acceptor_.close(); connection_manager_->stop_all(); } void server_impl::start_accept() { new_connection_.reset(new connection_impl( io_context_, connection_manager_, request_handler_)); acceptor_.async_accept( new_connection_->socket(), boost::bind( &server_impl::handle_accept, this, boost::asio::placeholders::error)); } void server_impl::handle_accept(const boost::system::error_code& e) { if (!acceptor_.is_open()) { return; } if (!e) { connection_manager_->start(new_connection_); } start_accept(); } void server_impl::serve_static(const std::string& path) { request_handler_->serve_from_directory(path); }
重启测试代码:
int main() { server->serve_static("/path/to/html"); server->start_server(); std::thread t([&server](){sleep(30); server->end_server();}); io_context->run(); t.join(); server->start_server(); io_context->run(); // 此处立即返回,服务器未重启 }
原因分析
io_context::run()会在所有异步操作完成后退出,并将上下文置于停止状态。即使后续重新添加了新的异步操作(比如start_server()里的async_accept),直接调用run()时,因为上下文仍处于停止状态,会立即返回,不会处理新的异步任务。
解决方案
方案1:重启前调用io_context::restart()
在第二次调用io_context->run()之前,调用io_context->restart()重置上下文状态,清除停止标记,使其可以再次处理异步操作。
修改后的main函数:
int main() { server->serve_static("/path/to/html"); server->start_server(); std::thread t([&server](){sleep(30); server->end_server();}); io_context->run(); t.join(); // 重置io_context的停止状态 io_context->restart(); server->start_server(); io_context->run(); }
方案2:使用work对象保持io_context活跃(可选)
如果希望io_context始终处于可运行状态,不会因无工作任务而退出,可以在初始化时创建work守护对象。这样run()会一直阻塞,直到显式取消work对象。
示例代码:
int main() { // 创建work对象,保持io_context活跃 auto work_guard = boost::asio::make_work_guard(*io_context); server->serve_static("/path/to/html"); server->start_server(); std::thread t([&server, &work_guard](){ sleep(30); server->end_server(); // 取消work守护,让io_context可以退出 work_guard.reset(); }); io_context->run(); t.join(); // 重新创建work对象 work_guard = boost::asio::make_work_guard(*io_context); server->start_server(); io_context->run(); }
额外注意事项
end_server()中调用acceptor_.close()会正确取消所有未完成的异步accept操作,重启时start_server()重新打开、绑定、监听acceptor的逻辑是正确的。- 确保
connection_manager_->stop_all()能正确关闭所有活跃连接,避免残留异步任务干扰重启流程。
内容的提问来源于stack exchange,提问作者av4625
相关产品推荐
相关产品推荐

