Boost Beast HTTP服务器处理首次请求后异常退出问题排查
Boost Beast HTTP服务器处理首个请求后异常退出问题
我无法理解为何基于Boost Beast实现的HTTP服务器在处理完第一个请求后就异常退出,甚至未输出“Server has stopped running.”日志便自行终止。目前服务器能正常返回首次请求的响应,但之后便停止运行并退出程序。我已将此实现与官方小型HTTP服务器示例对比,但仍未找出退出原因,二者结构相近,仅服务器类的组织方式不同。
main.cpp
#include <iostream> #include <unordered_map> #include <memory> #include <boost/beast/core.hpp> #include <boost/beast/http.hpp> #include "..\include\server2.hpp" using namespace std; constexpr char ADDRESS[] = "0.0.0.0"; constexpr unsigned short PORT = 8080; constexpr char DOC_ROOT[] = "frontend"; int main(int argc, char* argv[]) { try { auto const address = boost::asio::ip::make_address(ADDRESS); unsigned short port = PORT; Server server(DOC_ROOT, address, port); server.run(); cout << " hello" << endl; } catch (std::exception const& e) { std::cout << "Error: " << e.what() << std::endl; return EXIT_FAILURE; } }
server2.hpp
#pragma once #include <iostream> #include <string> #include <unordered_map> #include <unordered_set> #include <fstream> #include <boost/asio.hpp> #include <boost/beast/core.hpp> #include <boost/beast/http.hpp> #include <boost/filesystem.hpp> #include "toggle_button.hpp" class Server { const boost::asio::ip::address m_address; const unsigned short m_port; const std::string m_docroot; boost::asio::io_context m_ioc; boost::asio::ip::tcp::acceptor m_acceptor; std::unordered_set<std::shared_ptr<boost::asio::ip::tcp::socket>> sse_clients; int i; public: Server(const std::string& docroot, const boost::asio::ip::address& address, const unsigned short& port) : m_docroot(docroot), m_address(address), m_port(port), m_ioc(1), m_acceptor(m_ioc, boost::asio::ip::tcp::endpoint(address, port)), i(1) {} void handle_accept() { auto new_socket = std::make_shared<boost::asio::ip::tcp::socket>(m_ioc); // Start asynchronous accept operation m_acceptor.async_accept(*new_socket, [new_socket, this](boost::system::error_code ec) { if (!ec) { // Start a new session with the accepted socket handle_session(std::move(new_socket)); } else { std::cerr << "Accept error: " << ec.message() << std::endl; } // Keep accepting new connections std::cout << " session << " << i++ << std::endl; handle_accept(); }); } void run() { std::cout << "Server is running and accepting connections..." << std::endl; // Start accepting connections handle_accept(); // Now run the io_context m_ioc.run(); std::cout << "Server has stopped running." << std::endl; } private: void handle_session(std::shared_ptr<boost::asio::ip::tcp::socket> socket) { auto buffer = std::make_shared<boost::beast::flat_buffer>(100000); auto request = std::make_shared<boost::beast::http::request<boost::beast::http::string_body>>(); boost::beast::http::async_read(*socket, *buffer, *request, [this, socket, buffer, request](boost::system::error_code ec, std::size_t bytes_transferred) mutable { if (!ec) { boost::beast::http::response<boost::beast::http::dynamic_body> response; response.result(boost::beast::http::status::ok); response.set(boost::beast::http::field::content_type, "text/html"); response.version(request->version()); response.keep_alive(false); response.set(boost::beast::http::field::server, "Beast"); boost::beast::ostream(response.body()) << "<html> " << "<head><title>Hello</title></head> " << "<body> " << "<h1>Hello world</h1> " << "<p>It's just me</p> " << "</body> " << "</html> "; response.prepare_payload(); boost::beast::http::async_write( *socket, response, [socket](boost::beast::error_code ec, std::size_t) { (*socket).shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); }); } else { std::cerr << "Read error: " << ec.message() << std::endl; } }); } };
问题根源
核心问题在于**io_context在所有异步操作完成后会自动停止运行**:
- 第一个请求的异步读、写操作完成后,socket被关闭,此时没有其他挂起的异步任务,
io_context.run()会直接返回,程序继续执行后续代码并退出,因此不会输出“Server has stopped running.”日志。 - 虽然
handle_accept中调用了自身来维持accept循环,但当io_context的任务队列耗尽时,后续的异步accept操作无法被调度。
修复方案
- 添加
executor_work_guard维持io_context运行
在Server类中添加work guard成员,阻止io_context在无任务时停止:
// Server类成员添加 boost::asio::executor_work_guard<boost::asio::io_context::executor_type> m_work; // 构造函数初始化 Server(const std::string& docroot, const boost::asio::ip::address& address, const unsigned short& port) : m_docroot(docroot), m_address(address), m_port(port), m_ioc(1), m_work(boost::asio::make_work_guard(m_ioc)), // 初始化work guard m_acceptor(m_ioc, boost::asio::ip::tcp::endpoint(address, port)), i(1) {}
- 优化socket回调中的资源管理
在async_write的回调中忽略shutdown的无关错误,让智能指针自动管理socket生命周期:
boost::beast::http::async_write( *socket, response, [socket](boost::beast::error_code ec, std::size_t) { if (!ec) { boost::system::error_code ignore_ec; socket->shutdown(boost::asio::ip::tcp::socket::shutdown_send, ignore_ec); } });
- 确保accept循环持续触发
当前handle_accept的实现已经在每次accept后递归调用自身,保持这个逻辑即可,即使出现accept错误也不会中断循环。
内容的提问来源于stack exchange,提问作者Jon Castillo
相关产品推荐
相关产品推荐

