基于 Boost.Asio 和 Boost.Beast 的异步 HTTP 服务器(学习记录)

已完成功能:

支持 GETPOST 请求的路由与回调处理。

解析URL请求。

单例模式 管理核心业务逻辑。

异步 I/O 技术和 定时器 控制超时。

通过回调函数注册机制,可以灵活地为不同的 URL 路由注册处理函数。

1. 项目背景

1.1 项目简介

本项目是一个基于 Boost.AsioBoost.Beast 的高性能 HTTP 服务器,实现了对 HTTP 请求的处理、路由功能和回调机制。该服务器使用 单例模式 来管理请求逻辑,并采用 异步 I/O 技术 来提升并发处理能力。支持的 HTTP 请求类型包括 GETPOST,并能够根据 URL 注册不同的处理函数,从而实现灵活的请求路由与回调处理机制。

1.2 项目目标

该项目旨在提供一个 高效可扩展 的 HTTP 服务器,适用于处理大量并发 HTTP 请求,具备以下核心目标:

  • 高并发处理能力:通过使用异步 I/O 和非阻塞 I/O 操作显著提升并发处理能力,避免因同步阻塞导致的性能瓶颈。
  • 可扩展性:支持通过注册回调函数来灵活处理不同的 HTTP 请求,能够根据需要扩展支持更多的 HTTP 请求类型和自定义业务逻辑。
  • 简洁的单例管理:使用单例模式管理全局资源,确保只有一个服务器实例和唯一的请求逻辑处理实例,避免重复初始化资源和管理多个实例的问题。
  • 超时管理 :通过 Boost.Asio 提供的定时器机制实现 HTTP 连接的超时控制,确保服务器能够及时关闭不活跃的连接,避免因连接泄漏导致的资源浪费。

2. 项目架构

2.1 架构概述

本项目采用了事件驱动的架构模型,基于 Boost.Asio 提供的异步 I/O 功能实现高效的请求处理。整个系统通过 CServer 启动并接受客户端的连接,HttpConnection 管理每个 HTTP 请求的连接,LogicSystem 处理请求的业务逻辑,利用 单例模式 确保请求处理逻辑的唯一性。各个模块协同工作,通过回调机制对请求进行处理。

服务器架构可以分为以下几个关键模块:

  • CServer:负责启动服务器,监听指定端口并接受客户端连接请求。
  • LogicSystem:使用单例模式管理 HTTP 请求的逻辑处理,负责路由注册与回调函数的执行。
  • HttpConnection:处理每个 HTTP 请求的连接,包括请求解析、响应构建以及连接超时管理。
  • Singleton:一个模板类,提供单例模式的实现,确保系统中逻辑处理系统和其他核心组件只有一个实例。
  • 回调函数 :通过回调函数类型 HttpHandler 处理 HTTP 请求,支持 GET 和 POST 请求的灵活处理。

2.2 模块划分

1.网络通信模块

该模块基于 Boost.Asio 库实现,用于管理异步的 TCP 连接和 HTTP 请求的处理。CServer 负责监听端口并接受客户端连接,HttpConnection 负责处理每个连接的 HTTP 请求,采用非阻塞 I/O 操作来保证服务器的高效性能。

关键类:

  • CServer :负责创建 acceptor 并等待连接,管理 tcp::socket
  • HttpConnection:负责处理 HTTP 请求和响应,管理 TCP 连接。
2.HTTP 请求处理模块

该模块基于 Boost.Beast 实现,负责解析 HTTP 请求和构建 HTTP 响应。使用 http::requesthttp::response 类型来处理请求和响应内容。该模块还通过回调函数 HttpHandler 进行路由处理。

关键类:

  • HttpConnection:解析请求并构建响应。
  • LogicSystem:注册并调用处理 GET/POST 请求的回调函数。
3.单例模式模块

通过模板实现的 Singleton 类,确保了系统中 LogicSystem 类等重要组件的唯一性。它通过懒汉式单例模式来延迟初始化,避免了不必要的资源浪费,确保系统的高效运行。

关键类:

  • Singleton :模板类,用于实现 LogicSystem 等核心组件的单例模式。
4.超时管理模块

Boost.Asiosteady_timer 被用于处理连接超时。每个 HTTP 连接都配备了一个定时器,如果连接在规定时间内没有收到有效响应,则会自动关闭连接,防止资源泄漏。

关键类:

  • HttpConnection :内部持有一个 steady_timer,用于处理每个连接的超时。

2.3 数据流

项目的数据流过程如下:

  1. CServer 启动并监听指定端口,等待来自客户端的 TCP 连接。
  2. 客户端连接请求到来时,CServer 使用 acceptor 接受连接,并为每个连接创建一个 HttpConnection 实例。
  3. HttpConnection 启动异步读取操作,接收客户端发送的 HTTP 请求,并将请求数据存储在 beast::flat_buffer 中。
  4. 在接收到完整的 HTTP 请求后,HttpConnection 会解析请求,提取 URL 和请求方法(如 GET 或 POST)。
  5. HttpConnection 将请求转交给 LogicSystemLogicSystem 根据请求的 URL 查找对应的回调函数(HttpHandler),并执行该回调函数进行处理。
  6. 回调函数处理完请求后,HttpConnection 将生成相应的 HTTP 响应,并异步将响应数据发送回客户端。
  7. 如果连接在规定时间内未完成处理,HttpConnection 会触发定时器,主动关闭连接,避免资源浪费。

3. 模块详细设计

由于代码太长,源码我给出链接

源码下载地址,密码:bhmyhttps://wwta.lanzoue.com/iqugu2k8shij

3.1 CServer 模块

CServer 类是整个 HTTP 服务器的入口,负责启动服务器,监听并接受来自客户端的连接。它依赖于 Boost.Asio 库提供的 tcp::acceptor 来监听指定的端口。当客户端连接到服务器时,CServer 会为每个连接创建一个新的 HttpConnection 对象来处理该连接。

关键函数:
  • Start():启动服务器并开始接受客户端连接。
  • Accept() :异步接受客户端连接,当有新的连接请求时调用 HttpConnection 来处理。

CServer 的主要任务是创建和管理连接,每当有新的连接请求时,它会为该连接创建一个 HttpConnection 对象,后者将负责处理 HTTP 请求。

cpp 复制代码
#ifndef CSERVER_H
#define CSERVER_H
#include "const.h"

// CServer 类,负责接受客户端连接并处理连接请求
class CServer :public std::enable_shared_from_this<CServer> {
public:
	CServer(boost::asio::io_context& ioc, unsigned short& port);// 构造函数:初始化服务器并绑定到指定端口
	void Start(); // 启动服务器,开始接受连接
private:
	tcp::acceptor _acceptor;// 用于接受 TCP 连接的接受器
	net::io_context& _ioc;// 提供 I/O 服务的上下文对象
	tcp::socket _socket;// 用于与客户端通信的套接字
};
#endif

3.2 HttpConnection 模块

HttpConnection 类管理每一个客户端的 HTTP 连接。它负责异步读取客户端请求,解析 HTTP 请求,查找 URL 对应的回调函数,并生成 HTTP 响应返回给客户端。此外,HttpConnection 还负责超时管理,通过 Boost.Asiosteady_timer 来确保每个连接的生命周期不会过长,从而避免资源泄漏。

关键函数:
  • Start():启动连接,开始处理 HTTP 请求。
  • HandleReq():处理 HTTP 请求,包括解析请求内容并根据请求方法调用相应的回调函数。
  • CheckDeadline():检查当前连接是否超时,超时则关闭连接。
  • WriteResponse():将生成的 HTTP 响应数据写入客户端。

HttpConnection 的任务是在接收到请求后,解析出请求的方法(GET/POST)、URL 和参数,并将其传递给 LogicSystem 来进行后续的处理。最终,将服务器的响应发送给客户端。

cpp 复制代码
#ifndef HTTPCONNECTION_H
#define HTTPCONNECTION_H
#include "const.h"

// HttpConnection 类,负责与客户端的 HTTP 连接
// 提供处理 HTTP 请求、定时器管理等功能
class HttpConnection :public std::enable_shared_from_this<HttpConnection> {
	friend class LogicSystem;// 允许 LogicSystem 访问 HttpConnection 的私有成员
public:
	HttpConnection(tcp::socket socket);// 构造函数:接受 TCP 套接字,初始化连接
	void Start(); // 启动连接处理
private:
	void CheckDeadline();// 检查是否超时,定时器功能
	void WriteResponse();// 写入响应数据
	void HandleReq(); // 处理 HTTP 请求
	void PreParseGetParam();//处理参数解析
	tcp::socket _socket;// 客户端套接字
	beast::flat_buffer _buffer{ 8192 };// 接收数据的缓冲区,最大缓存 8192 字节
	http::request<http::dynamic_body> _request;// HTTP 请求对象,存储接收到的 HTTP 请求数据
	http::response<http::dynamic_body> _response;// HTTP 响应对象,存储响应数据并发送给客户端
	// 定时器,检查连接是否超时,60 秒后自动关闭连接
	net::steady_timer deadline_{
		_socket.get_executor(),std::chrono::seconds(60)
	};
	std::string _get_url; // 存储请求的 URL
	std::unordered_map<std::string, std::string> _get_params;// 存储 GET 请求的查询参数,以键值对形式存储
};

#endif

3.3 LogicSystem 模块

LogicSystem 类是整个系统的核心,负责管理 HTTP 请求的路由与回调函数。它采用 单例模式 确保系统中只有一个逻辑处理实例,并通过 std::map 存储 GET 和 POST 请求的回调函数。每当 HTTP 请求到来时,HttpConnection 会将请求的 URL 传递给 LogicSystem,然后根据请求方法(GET/POST)查找并执行对应的回调函数。

关键函数:
  • RegGet():注册 GET 请求的回调函数。
  • RegPost():注册 POST 请求的回调函数。
  • HandleGet():处理 GET 请求,执行对应的回调函数。
  • HandlePost():处理 POST 请求,执行对应的回调函数。

LogicSystem 是一个单例类,它为每个请求类型(GET/POST)提供了 URL 到回调函数的映射表。当请求到来时,LogicSystem 会根据请求的 URL 查找相应的回调函数并执行,从而实现不同 URL 对应不同的处理逻辑。

cpp 复制代码
#ifndef LOGICSYSTEM_H
#define LOGICSTSTEM_H
#include "Singleton.h"
#include <functional>
#include <map>
#include "const.h"

class HttpConnection;

typedef std::function<void(std::shared_ptr<HttpConnection>)> HttpHandler;// 定义一个回调函数类型,处理 HTTP 请求
// HttpHandler 通过 shared_ptr 传递 HttpConnection 对象

// LogicSystem 类,用于管理 HTTP 请求的逻辑处理
// 采用单例模式,确保系统只有一个实例
class LogicSystem : public Singleton<LogicSystem> {
	friend class Singleton<LogicSystem>; // 允许 Singleton 类访问 LogicSystem 的构造函数
public:
	~LogicSystem();// 析构函数,负责释放资源
	bool HandleGet(std::string path, std::shared_ptr<HttpConnection> con); // 处理GET请求的函数
	bool HandlePost(std::string path, std::shared_ptr<HttpConnection> con);//处理POST请求的函数
	void RegGet(std::string url, HttpHandler handler);// 注册 GET 请求的回调函数
	void RegPost(std::string url, HttpHandler handler);// 注册POST请求的回调函数
private:
	LogicSystem(); // 构造函数,私有化以防外部直接创建实例
	//key为路由,value为回调函数
	std::map<std::string, HttpHandler> _post_handlers; // 存储 POST 请求的处理函数
	std::map<std::string, HttpHandler> _get_handlers; // 存储 GET 请求的处理函数
};
#endif

3.4 Singleton 模块

Singleton 模块通过模板实现了单例模式,确保系统中的核心组件(如 LogicSystem)只有一个实例。该模板类使用懒汉式初始化,确保在首次访问时才创建实例,并且每次访问都返回同一个实例。

关键函数:
  • GetInstance():获取单例实例,如果实例尚未创建,则进行初始化。
  • PrintAddress():打印当前单例实例的地址,便于调试。

Singleton 模块保证了系统中只有一个实例,可以有效避免重复实例化带来的资源浪费。通过使用 std::shared_ptr 管理实例的生命周期,确保实例的销毁是在所有引用都释放后进行的。

cpp 复制代码
#ifndef SINGLETON_H
#define SINGLETON_H
#include <mutex>
#include <iostream>
#include <memory>

// Singleton 模板类,确保一个类只有一个实例
// 使用 std::shared_ptr 来管理实例生命周期
template <typename T>
class Singleton {
protected:
	Singleton() = default;  // 默认构造函数,防止外部实例化
	Singleton(const Singleton<T>&) = delete; // 禁止拷贝构造
	Singleton& operator=(const Singleton<T>& st) = delete; // 禁止拷贝赋值

	static std::shared_ptr<T> _instance;// 存储单例实例的静态变量
public:
	// 获取单例实例,线程安全的懒汉式初始化
	static std::shared_ptr<T> GetInstance() {
		static std::once_flag s_flag;// 用于确保单例实例只被创建一次
		std::call_once(s_flag, [&]() {
			// 创建单例实例并保存在 _instance 中
			_instance = std::shared_ptr<T>(new T);
			});
		return _instance;// 返回单例实例
	}
	// 打印当前单例实例的地址
	void PrintAddress() {
		std::cout << _instance.get() << std::endl;
	}
	// 析构函数,打印销毁信息
	~Singleton() {
		std::cout << "this is singleton destruct" << std::endl;
	}
};

// 为单例提供静态变量的初始化
template<typename T>
std::shared_ptr<T>Singleton<T>::_instance = nullptr;
#endif

4.测试

输入http://localhost:8080/get_test

显示receive get_test req

输入http://localhost:8080/get_test?key1=value1&key2=value2

显示

复制代码
receive get_test req
param1key iskey1, value isvalue1
param2key iskey2, value isvalue2 
相关推荐
sunz_dragon6 分钟前
Claude Code / Codex Git 版本管理完整使用指南
服务器·人工智能
SPC的存折29 分钟前
3、主从复制实现同步数据过滤
linux·运维·服务器
SPC的存折31 分钟前
openEuler 24.03 MariaDB Galera 集群部署指南(cz)
linux·运维·服务器·数据库·mysql
SPC的存折44 分钟前
MySQL 8.0 分库分表
linux·运维·服务器·数据库·mysql
风吹迎面入袖凉1 小时前
【Redis】Redisson分布式锁原理
java·服务器·开发语言
day day day ...2 小时前
MyBatis条件误写引发的查询条件污染分析与防范
java·服务器·tomcat
TechMasterPlus3 小时前
Linux U-Boot 与内核启动流程深度解析:从上电到 Shell 的完整之旅
linux·运维·服务器
大白菜和MySQL3 小时前
Linux下dhcp服务搭建
linux·运维·服务器
SPC的存折3 小时前
1、MySQL故障排查与运维案例
linux·运维·服务器·数据库·mysql
Deitymoon3 小时前
linux——TCP服务器获取客户端IP地址
linux·服务器·tcp/ip