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对象,同时设置响应内容
  • 发送响应
    • 将生成的响应,转换为字符串格式,发送给客户端
  • 关闭连接
    • 处理请求和响应后,将连接放入到连接池中备用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/874268.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux实用操作三

文章目录 Linux实用操作三网络传输ping命令介绍&#xff1a;示例&#xff1a; wget命令介绍&#xff1a;示例&#xff1a; curl命令介绍&#xff1a;示例&#xff1a; 端口介绍&#xff1a;端口的划分&#xff1a;查看端口占用&#xff1a; 进程管理进程介绍&#xff1a;查看进…

基于WebGoat平台的SQL注入攻击

目录 引言 一、安装好JAVA 二、下载并运行WebGoat 三、注册并登录WebGoat 四、模拟攻击 1. 第九题 2. 第十题 3. 第十一题 4. 第十二题 5. 第十三题 五、思考体会 1. 举例说明SQL 注入攻击发生的原因。 2. 从信息的CIA 三要素&#xff08;机密性、完整性、可用性&…

【MySQL-17】存储过程-[变量篇]详解-(系统变量&用户定义变量&局部变量)

前言 大家好吖&#xff0c;欢迎来到 YY 滴MySQL系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Lin…

SpringBoot常用功能实现

1. 配置文件多环境配置 1.1 创建不同环境配置文件 文件名前缀和后缀为标准固定格式&#xff0c;不可以改变。 1.2 pom中加入文件配置 可以使用<activation>标签设置默认环境。 <profiles><profile><id>dev</id><activation><active…

内置华为视频终端API接口的中央控制系统

内置华为视频终端API接口的中控系统是一种高度集成化的智能控制系统&#xff0c;它通过将华为视频终端的控制功能集成到中控系统中&#xff0c;实现了对华为视频终端的远程控制和集中管理。以下是对该系统的详细介绍&#xff1a; 一、系统概述 该系统通过调用华为视频终端提供…

数据结构(队列及其实现)

概念与结构 概念&#xff1a;只允许在⼀端进⾏插⼊数据操作&#xff0c;在另⼀端进⾏删除数据操作的特殊线性表&#xff0c; 队列具有先进先出FIFO(First In First Out)原则。 ⼊队列&#xff1a;进⾏插⼊操作的⼀端称为队尾 出队列&#xff1a;进⾏删除操作的⼀端称为队头…

Python | Leetcode Python题解之第268题丢失的数字

题目&#xff1a; 题解&#xff1a; class Solution:def missingNumber(self, nums: List[int]) -> int:n len(nums)total n * (n 1) // 2arrSum sum(nums)return total - arrSum

texify - 识别数学/图像 PDF

文章目录 一、关于 texify例子训练 二、安装手动安装 三、使用1、使用技巧2、用于交互转换的应用程序3、转换图像4、Python 中导入并运行 四、限制五、基准测试运行自己的基准测试 六、其它商业用途感谢 一、关于 texify Texify是一种OCR模型&#xff0c;它将包含数学的图像或…

spring-retry详解

spring-retry详解 1.引入依赖2.Retryable基础使用3.Recover使用4.Retryable参数详解5.需要注意 重试机制对于大部分场景来说都是必要的&#xff0c;比如同步调用三方接口&#xff0c;三方接口、信息拉取等网络原因突然不通&#xff0c;有了重试就可以多一些容错机制&#xff0c…

HackTheBox--Knife

Knife 测试过程 1 信息收集 端口扫描 80端口测试 echo "10.129.63.56 knife.htb" | sudo tee -a /etc/hosts网站是纯静态的&#xff0c;无任何交互功能&#xff0c;检查网页源代码也未发现任何可利用的文件。 检查页面请求时&#xff0c;请求与响应内容&#xff0…

笔记小结:卷积神经网络之多输入多输出通道

本文为李沐老师《动手学深度学习》笔记小结&#xff0c;用于个人复习并记录学习历程&#xff0c;适用于初学者 彩色图像具有标准的RGB通道来代表红、绿和蓝&#xff0c;需要三个通道表示&#xff0c;故而只有单输入单输出是不够的。 对于单个输入和单个输出通道的简化例子&…

vscode配置latex环境制作【文档、简历、resume】

vscode配置latex环境制作【文档、简历、resume】 1. 安装Tex Live及vscode插件 可以参考&#xff1a;vscode配置latex环境制作beamer ppt 2. 添加vscode配置文件 打开vscode&#xff0c;按下Ctrl Shift P打开搜索框&#xff0c;搜索Preference: Open User Settings (JSON…

深入理解Linux网络(四):TCP接收阻塞

TCP socket 接收函数 recv 发出 recvfrom 系统调用。 进⼊系统调⽤后&#xff0c;⽤户进程就进⼊到了内核态&#xff0c;通过执⾏⼀系列的内核协议层函数&#xff0c;然后到 socket 对象的接收队列中查看是否有数据&#xff0c;没有的话就把⾃⼰添加到 socket 对应的等待队列⾥…

Conda和Pip有什么区别?

conda和pip是Python中两种常用的包管理工具&#xff0c;它们在用途、包来源以及环境管理等方面存在区别。以下是具体分析&#xff1a; 用途 conda&#xff1a;conda是Anaconda发行版中的包管理工具&#xff0c;可以管理包括非Python软件包在内的各种包。它是一个全面的环境管理…

为什么企业一定要多参加展会,参展有何好处?

在当今的商业环境中&#xff0c;展会已成为企业不可或缺的市场推广和交流平台。无论企业规模大小&#xff0c;参展都是一个极其有益的选择。以下&#xff0c;我们将深入探讨企业为何要多参加展会&#xff0c;以及参展所能带来的种种好处。 一、增强品牌影响力与知名度 展会是聚…

大数据量接口响应慢-传输优化

问题 接口一次性返回大量数据&#xff0c;导致JSON数据大小过大&#xff0c;带宽大小不足&#xff0c;导致接口响应时间过长 解决方案 通过数据传输压缩来降低传输数据的大小&#xff0c;从而提高传输效率 服务器端压缩 springboot项目配置application文件&#xff0c;通过…

视频翻译保留原音色pyvideotrans+clone-voice

剪映的视频翻译时长限制5分钟以内&#xff0c;需要积分2700首次有减免大概21.6元&#xff08;1秒9积分/1元100积分&#xff09; • 视频翻译配音工具pyvideotrans 将视频从一种语言翻译为另一种语言&#xff0c;并添加配音 打包链接&#xff1a;夸克网盘分享 升级补丁&#…

MySQL通过bin-log恢复数据

MySQL通过bin-log恢复数据 1.bin-log说明2.数据恢复流程2.1 查看是否开启bin-log2.3 查看bin-log2.4 执行数据恢复操作2.5 检查数据是否恢复 1.bin-log说明 mysqldump和bin-log都可以作为MySQL数据库备份的方式&#xff1a; mysqldump 用于将整个或部分数据库导出为可执行的S…

cms wpscan使用方式--kali linux

WPScan是一个用于WordPress安全审计和漏洞扫描的工具&#xff0c;可以通过以下命令来使用WPScan&#xff1a; 扫描一个网站&#xff1a; wpscan --url http://example.com扫描一个网站并指定用户名和密码&#xff1a; wpscan --url http://example.com --useradmin --passwo…