基于Boost.Beast的简易HTTP服务器异常问题求助
基于Boost.Beast的HTTP服务器问题修复
问题概述
当前服务器存在两个异常:
- 处理第二个请求时服务器关闭
- 无法返回FileCollector缓存的文件内容
代码问题分析与修复
问题1:第二个请求导致服务器关闭
核心问题点
- socket引用悬空:
start_acceptor参数tcp::socket& sock被复用,第一次std::move(sock)后,引用指向已失效对象,后续accept操作出错 - shared_ptr所有权错误转移:
std::move(fc)将FileCollector的智能指针所有权转移给第一个连接,后续连接拿到空指针 - 强制关闭持久连接:
response_.keep_alive(false)强制客户端关闭连接,且响应完成后未重启请求读取逻辑
修复后的start_acceptor代码
void ownHTTPServer::start_acceptor(tcp::acceptor& accepter, std::shared_ptr<Collector::FileCollector>& fc) { // 每次accept创建新socket,避免引用悬空 tcp::socket sock(accepter.get_executor()); accepter.async_accept(sock, [&, fc](beast::error_code er){ if (!er) { // 传递shared_ptr拷贝,确保所有连接共享同一缓存 std::make_shared<ownHTTPServer::http_connection>(std::move(sock), fc)->start(); } start_acceptor(accepter, fc); }); }
修复http_connection的连接逻辑(支持持久连接)
void http_connection::process_request(void) { response_.version(request_.version()); // 根据请求头决定是否保持连接,而非强制关闭 response_.keep_alive(request_.keep_alive()); switch (request_.method()) { case http::verb::get: response_.result(http::status::ok); response_.set(http::field::server, "Beast"); create_response(); break; default: response_.result(http::status::bad_request); response_.set(http::field::content_type, "text/plain"); beast::ostream(response_.body()) << "Invalid request-method '" << std::string(request_.method_string()) << "'"; break; } write_response(); } void http_connection::write_response(void) { auto self = shared_from_this(); response_.content_length(response_.body().size()); http::async_write( socket_, response_, [self](beast::error_code er, std::size_t bytes_trans) { boost::ignore_unused(bytes_trans); if (!er && self->response_.keep_alive()) { // 重置请求响应,读取下一个请求 self->request_ = {}; self->response_ = {}; self->read_request(); return; } // 关闭连接 self->socket_.shutdown(tcp::socket::shutdown_send, er); } ); }
问题2:无法返回FileCollector缓存内容
核心问题点
- FileCollector的
get_file_data未实现正确的文件读取与缓存逻辑 create_response未处理文件不存在的情况,返回空内容
完善FileCollector实现
#include <fstream> #include <stdexcept> Collector::FileCollector::FileCollector() {} std::string Collector::FileCollector::get_file_data(std::string filename) { // 检查缓存 auto it = fileData.find(filename); if (it != fileData.end()) { return it->second; } // 读取文件 std::ifstream file(filename, std::ios::binary | std::ios::ate); if (!file.is_open()) { throw std::runtime_error("File not found: " + filename); } std::streamsize size = file.tellg(); file.seekg(0, std::ios::beg); std::string content(size, '\0'); if (!file.read(&content[0], size)) { throw std::runtime_error("Failed to read file: " + filename); } // 存入缓存 fileData[filename] = content; return content; }
修改create_response处理异常
void http_connection::create_response(void) { std::string_view sv = request_.target().substr(1); std::string targetfile = {sv.data(), sv.size()}; try { std::string content = filecollector->get_file_data(targetfile); response_.set(http::field::content_type, "text/plain"); // 可根据文件后缀优化 response_.body() = std::move(content); } catch (const std::exception& e) { response_.result(http::status::not_found); response_.set(http::field::content_type, "text/plain"); beast::ostream(response_.body()) << "File not found: " << e.what(); } }
Boost.Asio学习内容推荐
- 基础入门:先掌握核心概念:io_context、异步操作、回调函数、strand(线程安全)、socket类型。从同步TCP/UDP通信开始,再过渡到异步模式。
- 核心组件:重点学习
boost::asio::ip::tcp相关类(acceptor、socket),异步操作的错误处理,以及智能指针在异步回调中的使用(避免对象提前销毁)。 - Beast结合使用:理解Boost.Beast是基于Asio的HTTP/WebSocket库,掌握HTTP请求/响应的解析与构造,异步读写流程。
- 实战案例:参考Boost官方提供的Beast HTTP服务器/客户端示例,逐步拆解代码逻辑,理解每个步骤的作用。
- 线程模型:学习Asio的多线程处理方式,如何用多个io_context线程提升并发性能,以及strand的使用场景。
内容的提问来源于stack exchange,提问作者Simple Boy
相关产品推荐
相关产品推荐

