HTTPServer改进思路2(mudou库核心思想融入)
mudou网络库思想理解
Reactor与多线程
服务器构建过程中,不仅仅使用一个Reactor,而是使用多个Reactor,每个Reactor执行自己专属的任务,从而提高响应效率。
首先Reactor是一种事件驱动处理模式,其主要通过IO多路复用机制统一监听想要关心的事件,如果关心的事件有响应后,则将该响应事件分发给进程或者线程去处理,从而提高网络服务器的性能。简单可以理解为服务器利用该模式处理多路请求,然后将它们同步的分发给线程或者进程去处理。
其次构建服务器可以使用多个Reactor,从而来提高服务器对事件的响应效率。将负责连接与客户端通信监控分离开,则是一个Reactor专门负责连处理新连接的请求事件,如果发现有新的连接,则将其分发给子Reactor中去监控,另一个Reactor则主要负责监控客户端是否发送了请求或者其他事件,如果有事件触发,则将其交给线程池处理。
主线Reactor处理新连接 ---->交给子Reactor进行监控 ——>事件发生交给线程处理
最后,Reactor需要将待处理的任务交付给线程或者进程去处理,如果想要使得服务器效率高,肯定要避免线程或者进程的频繁的创建销毁,这样会占用服务器的性能。所以构建线程池与Reactor配合,有助于减少性能消耗。
任务线程池的主要作用则是分配独立的线程去执行Reactor中需要处理的任务,最后将处理好的数据交给Reactor线程,让其完成对客户端的响应。
One Loop Per One Thread
主Reactor负责获取连接,获取新连接后,将新连接分发给子Reactor进行网络通信的事件处理。子Reactor监控各个描述符下的读写等事件,当事件响应的时候分发给线程池中的线程去处理。
主要思想是将某一事件所有的操作放在一个线程中进行,即一个线程对应着一种事件的处理,而每个 Reactor都可以使用线程池让其为自己服务,从而可以并发的实现请求的响应。(每个线程与一个独立的事件循环绑定)
核心思想分析
- 事件驱动
- 每个线程都绑定一个事件循环,处理一系列非阻塞的IO事件
- 事件循环,则是通过事件队列接收事件,同事根据事件类型和回调函数执行该事件对应的操作
- 线程与事件绑定
- 线程间独立运行自己的事件循环,而不会与其他线程共享事件循环
- 这样的好处在于,避免了线程竞争,从而提高并发效率
- 非阻塞I/O
- 事件循环的过程中,I/O操作都是非阻塞的,这样一来,线程就不会因为等待I/O操作,而阻塞等待
- 实现一个线程在同一时间内,可以处理多个I/O请求,从而提高系统的吞吐量
- 任务调度与并发
- 任务被分发到不同的线程,各个线程可以独立处理自己的任务序列
- 通过该方式,可以借助负载均衡机制,确保各个线程的工作量均衡,从而防止某个线程过载。
- 编程简化
- 一个线程对应一个事件循环,所以并发程序的设计过程中,无需考虑线程同步与锁的机制
- 只需要关注如何处理事件以及回调函数即可
一个线程绑定的事件在服务器中通常都是I/O事件
- 连接事件
- 建立连接:客户端尝试连接服务器的时候,服务器的监听线程会收到一个连接建立的事件(Accept)。
- 服务器接收这个连接后,将其分配一个工作线程去处理。(在该网络库的思想中,服务器接收连接后,会将其交给子Reactor监控,子Reactor监控到事件发生后,再从线程池中调取线程去执行)
- 读事件
- 数据到达:客户端发送请求数据到达服务器的时候,服务器的线程收到一个读事件,此时监控读事件的Reactor开始响应。从线程池中调用线程去读取数据,解析HTTP请求,并根据请求的内容做出对应处理
- 写事件
- 数据可写事件:服务器准备好响应数据,并准备将该响应数据发送给客户端的时候,服务器此时会触发写事件,表示可以将数据写入到客户端的连接中。
- 关闭事件
- 连接关闭事件:客户端或者服务端关闭连接的时候,触发这个关闭事件,服务器需要清理相应的资源,确保连接正常关闭,避免该连接浪费服务器资源。
项目改进架构思路
服务器架构通过多线程和事件驱动的架构来高效的处理大量并发请求。服务器同时采用非阻塞I/O模式,避免了阻塞操作带来的性能瓶颈,从而让服务器可以高效的处理大量并发请求。

主要模块功能逻辑
Main Reactor
- 初始化
- 创建EventLoop实例
- 创建并初始化Acceptor,设置监听端口和回调函数
- 接受新连接
- Acceptor中,监听新连接请求
- 使用accept系统调用,同时调用回调函数,为新连接进行对应封装
- 分发新连接
- 主Reactor将新连接分配给Reactor,创建Channel对象管理连接
Sub Reactor
- 初始化
- 创建EventLoop对象
- 创建独立线程去运行EventLoop(一个线程一个Reactor思想)
- 处理I/O事件
- EventLoop中通过EPOLL等待关心事件发生
- 将发生的事件分配给Channel对象
- 事件处理
- Channel根据事件的类型,调用注册的回调函数
- 读事件处理:读取数据并解析HTTP请求
- 写事件处理:发送HTTP响应
Epoller逻辑
- 初始化
- 创建EPOLL实例
- 管理文件描述符
- 添加、更新和删除文件描述符
- 等待监控事件发生
- 利用epoll_wait 等待事件的发生
HttpServer逻辑
- 初始化
- 创建HttpServer实例,同时继承TcpServer的功能
- 注册HTTP请求处理函数
- 处理HTTP请求
- 解析HTTP请求,生成HttpRequsest对象
- 根据请求的路径调用相应的处理函数
- 生成并发送响应
- 调用处理函数后生成HttpResponse对象
- 将响应转化为字符串的形式发送给客户端
Main逻辑
- 注册处理函数
- 注册URL路径以及对应的处理函数
- 处理具体业务逻辑
- 根据具体的需求,处理HTTP请求并生成响应
代码架构设计
Server
#ifndef SERVER_HPP
#define SERVER_HPP#include <vector>
#include <functional>
#include <memory>
#include <sys/epoll.h>
#include <unistd.h>class Channel;
class EventLoop;class Epoller {
private:int _epollFd;std::vector<epoll_event> _events;public:Epoller();~Epoller();void UpdateChannel(Channel* channel);void RemoveChannel(Channel* channel);void Poll(std::vector<Channel*>& activeChannels);
};class Channel {
private:EventLoop* _loop;const int _fd;uint32_t _events;uint32_t _revents;std::function<void()> _readCallback;std::function<void()> _writeCallback;public:Channel(EventLoop* loop, int fd);void SetReadCallback(const std::function<void()>& cb);void SetWriteCallback(const std::function<void()>& cb);void EnableReading();void EnableWriting();void DisableWriting();void DisableAll();void Remove();void HandleEvent();void Update();int Fd() const;uint32_t Events() const;uint32_t Revents() const;void SetRevents(uint32_t revents);
};class EventLoop {
private:bool _quit;std::vector<Channel*> _activeChannels;Epoller _poller;public:EventLoop();void Loop();void Quit();void UpdateChannel(Channel* channel);void RemoveChannel(Channel* channel);
};class Acceptor {
private:EventLoop* _loop;int _listenFd;std::function<void(int)> _newConnectionCallback;public:Acceptor(EventLoop* loop, int port);void SetAcceptCallback(const std::function<void(int)>& cb);void Listen();void HandleRead();
};class SubReactor {
private:EventLoop _loop;std::thread _thread;public:SubReactor();void Run();EventLoop* GetLoop();void Join();
};class MainReactor {
private:EventLoop _loop;Acceptor _acceptor;std::vector<SubReactor*> _subReactors;int _nextReactor;public:MainReactor(int port, int subReactorCount);void NewConnection(int fd);void Run();void JoinSubReactors();
};#endif // SERVER_HPP
HTTP
#ifndef HTTP_HPP
#define HTTP_HPP#include "server.hpp"
#include <unordered_map>
#include <functional>
#include <string>class HttpRequest {
public:std::string _method;std::string _path;std::string _version;std::unordered_map<std::string, std::string> _params;std::unordered_map<std::string, std::string> _headers;std::string _body;// 解析请求
};class HttpResponse {
public:int _status;std::unordered_map<std::string, std::string> _headers;std::string _body;void SetContent(const std::string& content, const std::string& type) {_body = content;_headers["Content-Type"] = type;}// 响应
};class HttpServer : public TcpServer {
private:std::unordered_map<std::string, std::function<void(const HttpRequest&, HttpResponse*)>> _handlers;public:HttpServer(int port);void RegisterHandler(const std::string& path, const std::function<void(const HttpRequest&, HttpResponse*)>& handler);void OnMessage(const PtrConnection& conn, const std::string& message);
};#endif // HTTP_HPP
main
#include "http.hpp"#define WWWROOT "./wwwroot/"int main() {HttpServer server(8888);server.Start();return 0;
}
细节问题梳理
Reactor、Channel|、epoll三者结合
多Reactor模型中三者结合分析
- 每个Reactor都拥有自己的epoll实例:具体也就是每个EventLoop(Reactor)都拥有自己属于自己的epoll实例来管理文件描述符和就绪事件
- 每个Channel对象与一个文件描述符和一个Reactor(EventLoop)关联:新连接到来时,主Reactor接受新连接请求后,将文件描述符分配给子Reactor,子Reactor创建一个Channel对象来管理文件描述符
- 事件循环独立运行:每个EventLoop都是独立运行,用于管理文件描述符上关心的事件
新连接创建后其文件描述符作用
- 主Reactor接收新连接后,accept会返回这个连接的文件描述符,然后将其分发给对应的子Reactor中
- 子Reactor管理连接:Channel类负责将文件描述符上的(读写)事件通知到对应的处理函数
进程与线程关系梳理/新连接文件描述符管理问题
- 首先,服务器启动后作为一个进程运行,多个Reactor则是该进程下的线程
- 主Reactor和子Reactor都是在服务器下作为线程执行
- 每个Reactor线程有自己的文件描述符,管理客户端连接(自己需要关心的特定事件)
- 新连接到来后,内核又会为新连接创建一个新的文件描述符
- 主Reactor又会将这个新获取的文件描述符分发给子Reactor中进行管理和处理
线程池和和任务队列的处理
- 主Reactor接收新连接后,将新连接分发给子Reactor中进行管理和处理
- 子Reactor处理I/O事件后,将其放入任务队列
- 线程池中的线程取出任务并执行任务
- 线程池与事件循环放在一起,子Reactor线程将任务交给线程池处理即可
请求到响应流程分析
- 服务器初始化
- 监听端口;设置线程数量(Reactor数量)注册处理函数
- 启动服务器接口
- 接收新连接
- 主Reactor监听新连接,新连接到达后通过NewConnetion方法将连接分发给从Reactor中进行管理
- 分发连接
- 主Reactor借助LoopThreadPool将新连接交给子Reactor中的EventLoop中进行处理
- 处理请求
- 子Reactor线程的EventLoop处理分配到的连接
- 读取请求数据,同时将其解析为HttpRequest对象
- 调用注册的处理函数对请求进行处理
- 生成响应
- 处理数据,根据传入的请求,生成HttpResponse对象,同时设置响应内容
- 发送响应
- 将生成的响应,转换为字符串格式,发送给客户端
- 关闭连接
- 处理请求和响应后,将连接放入到连接池中备用
相关文章:
HTTPServer改进思路2(mudou库核心思想融入)
mudou网络库思想理解 Reactor与多线程 服务器构建过程中,不仅仅使用一个Reactor,而是使用多个Reactor,每个Reactor执行自己专属的任务,从而提高响应效率。 首先Reactor是一种事件驱动处理模式,其主要通过IO多路复用…...
Kubernetes Secret 详解
Kubernetes Secret 是一种用于存储和管理敏感信息的对象,如密码、OAuth 令牌和 SSH 密钥等。使用 Secret 可以避免将机密数据直接放在 Pod 规约或容器镜像中,从而增加了应用程序的安全性。 Secret 的类型 Kubernetes 支持多种类型的 Secret,包括: Opaque:默认的…...
docker笔记4-部署
docker笔记4-部署 一、部署nginx二、部署Tomcat三、部署ESKibana3.1 部署ES3.2 部署kibana 一、部署nginx docker search nginx #搜索nginx的最新版本docker pull nginx #这里可以指定nginx版本,如果不指定,那么就拉取最新版本latestdocker run -d --na…...
有监督学习基础
基本概念 给定输入有为(x,y),其中x表示学习特征,y表示输出,m表示输入总数,有监督学习旨在根据输入建立能够预测可能输出的模型,大致可以分为回归和分类两种,代表可能输出是无限的或…...
揭开 AI 绘画提示词的神秘密码!
前言 ** 揭秘AI 绘画 ** 提示词的神秘密码 亲爱的朋友们,今天我们要一起探索 AI 绘画世界中那神秘的“密码”——提示词。 在 AI 绘画的奇妙领域里,提示词就像是一把神奇的钥匙,能够开启无尽的创意之门。它是我们与 AI 进行心灵对话的桥…...
macOS 10.15中屏蔽Microsoft Edge浏览器的更新提示
文章目录 1.效果对比2.安装描述文件3.停用描述文件4.高级操作(可选)参考文献 最近在macOS10.15系统,打开Microsoft Edge浏览器,每次打开都有个烦人的提示“ 要获取将来的 microsoft edge 更新,需要 macos 10.15 或更高…...
Qt 实战(3)数据类型 | 3.2、QVariant
文章目录 一、QVariant1、存储数据1.1、存储Qt内置数据1.2、存储自定义数据 2、获取数据3、判断数据类型4、清空数据5、总结 前言: QVariant是Qt框架中一个非常强大且灵活的类,它提供了一种通用的方式来存储和转换几乎任何类型的数据。无论是基本数据类型…...
Docker中安装的postgresql14在启用vector扩展的时候,找不到该扩展的控制文件。
ERROR: could not open extension control file “/usr/share/postgresql/14/extension/vector.control”: No such file or directory 进入容器 docker exec -it CONTAINER ID /bin/bash 1.更新 apt-get apt-get update 2.安装插件 #不同版本对应修改数字即可 apt-get i…...
JS防抖和节流
一、防抖和节流的适用场景 防抖(Debounce): 适合在输入框输入时的实时搜索、窗口大小调整时的resize事件等。节流(Throttle): 适合如页面滚动时的scroll事件、按钮点击时的请求发送等需要控制频率的场景。 …...
OpenWrt 为软件包和docker空间扩容
参考资料 【openwrt折腾日记】解决openwrt固件刷入后磁盘空间默认小的问题,关联openwrt磁盘扩容空间扩容【openwrt分区扩容】轻松解决空间可用不足的尴尬丨老李一瓶奶油的YouTube 划分空间 参考一瓶奶油的YouTube 系统 -> 磁盘管理 -> 磁盘 -> 修改 格…...
重要的工作任务,怎么在电脑桌面设置倒计时?
在日常工作中,我们总是面临着众多工作任务,如何高效地管理和完成这些任务成为了每个职场人的必备技能。为任务设置倒计时,不仅能让我们清晰地看到任务的先后顺序,还能帮助我们更好地把握时间,提高工作效率。想象一下&a…...
Failed to build get_cli:get:的解决方案
项目场景: 今天安装Getx命令行的时候,输入这面文档报了一个错: dart pub global activate get_cli 问题描述 提示:这里描述项目中遇到的问题: 例如:数据传输过程中数据不时出现丢失的情况,偶尔…...
短视频矩阵源码技术分享
在当今数字媒体时代,短视频已成为吸引观众和传递信息的重要手段。对于开发者而言,掌握短视频矩阵源码技术不仅是提升自身技能的需要,更是把握行业发展趋势的必然选择。本文将深入探讨短视频矩阵源码的关键技术要点及其实现方法,帮…...
轮播图自定义内容
官网:Swiper演示 - Swiper中文网 下载: npm i swiper Vue3示例代码: <template><div class"swiper mySwiper"><div class"swiper-wrapper"><div class"swiper-slide"><div>…...
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...
Istio_01_Istio初识
文章目录 IstioService Mesh Istio Istio: 以服务网格形态用于服务治理的开放平台和基础设施 本质: 以非侵入式治理服务之间的访问和调用服务治理: 流量管理、可观测性、安全性可同时管理多类基础设施(多种网络方案) 如: Istio和Kubernetes架构的结合 Istio通过Kubernetes的域…...
leetcode日记(47)螺旋矩阵Ⅱ
这题思路不难,就是找规律太难了。 我首先的思路是一行一行来,根据规律填入下一行的数组,第i行是由前i个数字(n-2*i)个增序数列后i个数字组成,后来觉得太难找规律了就换了一种思路。 思路大致是先计算出需…...
centos系统mysql主从复制(一主一从)
文章目录 mysql80主从复制(一主一从)一、环境二、服务器master1操作1.开启二进制日志2. 创建复制用户3. 服务器 slave1操作4. 在主数据库中添加数据 mysql80主从复制(一主一从) 一、环境 准备两台服务器,都进行以下操…...
IEDA怎么把springboot项目 启动多个
利用Idea提供的Edit Configurations配置应用参数。 点击Modify Options进行添加应用参数: 确保这里勾选...
Vue 3项目安装Element-Plus
Element Plus 是一个基于 Vue 3 的现代前端UI框架,它旨在提升开发体验,并为开发者提供高效、优雅的组件。如果你正在使用 Vue 3 进行项目开发,那么安装和集成 Element Plus 是一个不错的选择。在本文中,博主将详细介绍如何在 Vue …...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
