当前位置: 首页 > news >正文

【C++网络编程】番外篇(实战):基于Boost.Asio协程的HTTP服务器实现与静态文件服务开发指南

一、引言:协程化网络编程的优势

在传统的同步IO模型中,每个连接需要独占线程资源,当面对高并发场景时会产生巨大的线程切换开销。Boost.Asio的协程支持通过以下方式解决这个问题:

  1. 无栈协程(Stackless Coroutine)​
    基于C++20协程TS实现,每个协程仅需约1KB内存
  2. ​协作式调度
    通过co_await关键字实现非阻塞等待,避免线程切换
  3. 天然异步集成
    与Asio的异步IO模型完美结合,实现高效资源利用

二、核心实现:HTTP协议解析器

1. HTTP请求结构体定义

struct http_request {std::string method;         // 请求方法(GET/POST等)std::string path;           // 请求路径(如"/index.html")std::map<std::string, std::string> headers; // 请求头键值对std::string body;           // 请求体内容
};

2. 协程化请求解析函数

asio::awaitable<http_request> parse_http_request(tcp::socket& socket) {http_request req;                     // 存储解析结果beast::flat_buffer buffer;            // 高效二进制缓冲区http::request_parser<http::dynamic_body> parser; // 动态body解析器// 关键步骤1:异步读取请求头co_await http::async_read_header(socket, buffer, parser, asio::use_awaitable);auto& msg = parser.get(); // 获取解析后的消息对象

3. 请求方法解析

// 将boost::string_view转换为std::string
req.method = std::string(msg.method_string());
  • 方法来源method_string()返回boost::beast::string_view
  • 转换必要性:避免原始数据被缓冲区释放后失效
  • 支持方法:自动处理GET/POST/PUT/DELETE等标准方法

4. 请求路径处理

req.path = std::string(msg.target()); // 原始请求路径
  • 示例输入:/api/status
  • 注意点:此时路径包含原始查询字符串,需后续处理
  • 安全性:需要后续的路径消毒(sanitize_path)

5. 请求头解析

for (auto const& field : msg) {std::string name = std::string(field.name_string());std::string value = std::string(field.value());req.headers[name] = value;
}
  • 遍历机制:msg实现了begin/end迭代器
  • 头字段示例:
    a)Content-Type: application/json
    b)Authorization: Bearer token
  • 大小写处理Boost.Beast自动转换为小写键名

6. 请求体处理

if (parser.content_length().value_or(0) > 0) {co_await http::async_read(socket, buffer, parser, asio::use_awaitable);req.body = beast::buffers_to_string(parser.get().body().data());
}
  • 条件判断:仅当存在有效Content-Length时读取body
  • 异步读取:继续从socket读取剩余数据
  • 数据转换:将多个buffer片段拼接为完整字符串
  • 性能考量:对于大文件应考虑流式处理

7. 完整代码

//http_parser.hpp
#pragma once
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <sstream>
#include <map>namespace asio = boost::asio;
namespace beast = boost::beast;
namespace http = beast::http;
using tcp = asio::ip::tcp;struct http_request {std::string method;std::string path;std::map<std::string, std::string> headers;std::string body;
};asio::awaitable<http_request> parse_http_request(tcp::socket& socket) {http_request req;beast::flat_buffer buffer;http::request_parser<http::dynamic_body> parser;// 读取请求头co_await http::async_read_header(socket, buffer, parser, asio::use_awaitable);auto& msg = parser.get();// 1: 转换methodreq.method = std::string(msg.method_string());// 2: 转换target路径req.path = std::string(msg.target());// 3: 转换headersfor (auto const& field : msg) {std::string name = std::string(field.name_string());std::string value = std::string(field.value());req.headers[name] = value;}// 4: 转换body内容if (parser.content_length().value_or(0) > 0) {co_await http::async_read(socket, buffer, parser, asio::use_awaitable);req.body = beast::buffers_to_string(parser.get().body().data());}co_return req;
}

三、通用工具类

1. 通用响应函数

asio::awaitable<void> send_response(tcp::socket& socket,http::status status,const std::string& body = "") {http::response<http::string_body> res;res.result(status);res.set(http::field::server, "AsioHTTP/1.0");res.body() = body;res.content_length(body.size());co_await http::async_write(socket, res, asio::use_awaitable);
}

应用场景

  • 发送错误响应(404/500等)
  • 返回简单文本信息
  • 调试信息输出

2. 完整代码

//utils.hpp
#pragma once
#include <boost/asio.hpp>asio::awaitable<void> send_response(tcp::socket& socket,http::status status,const std::string& body = "") 
{http::response<http::string_body> res;res.result(status);res.set(http::field::server, "AsioHTTP/1.0");res.body() = body;res.content_length(body.size());co_await http::async_write(socket, res, asio::use_awaitable);
}

四、API处理类

1. send_json函数

asio::awaitable<void> send_json(tcp::socket& socket, const json& data) {http::response<http::string_body> res;res.result(http::status::ok);                      // 设置状态码200res.set(http::field::content_type, "application/json"); // 内容类型res.body() = data.dump();                          // JSON序列化res.content_length(res.body().size());             // 显式设置内容长度co_await http::async_write

http://www.mrgr.cn/news/96021.html

相关文章:

  • macOS 制作dmg磁盘映像安装包
  • 2.0 项目管理前言
  • 车载以太网网络测试 -24【SOME/IP概述】
  • 科普:特征、规则、模型,及Lift(提升度)
  • PyTorch图像预处理--Compose
  • Linux面试题
  • 优选算法系列(4.前缀和 _下) k
  • CAS(Compare And Swap)
  • 23种设计模式-观察者(Observer)设计模式
  • ElasticSearch -- 部署完整步骤
  • 黑盒测试与白盒测试详解
  • dynamic_cast的理解
  • LangChain4j(1):初识LangChain4j
  • Matlab Hessian矩阵计算(LoG算子)
  • kafka零拷贝技术的底层实现
  • 《Operating System Concepts》阅读笔记:p483-p488
  • Vala编成语言教程-构造函数和析构函数
  • 人员进出新视界:视觉分析算法的力量
  • 全书测试:《C++性能优化指南》
  • element与elementplus入门