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.rhkb.cn/news/382518.html

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

相关文章

ST Stellar-E SR5E1 22KW OBC combo 3KW DC-DC汽车充电器解决方案

对于全球的环境保护意识抬头&#xff0c;全球的汽车产业慢慢步入电动化的时代&#xff0c;以减少碳排放。整车系统主要是由电池、电驱、电控的三电所构成&#xff0c;其中电池系统是整车的动力来源&#xff0c;而对电池充电的OBC系统更甚重要。一具高度安全性且高效的OBC系统&a…

7.23 字符串简单中等 520 125 14 34

520 Detect Capital 思路&#xff1a; 题目&#xff1a;判定word &#xff1a;if the usage of capitals in it is right.遍历所有的string&#xff1a; 两种情况&#xff1a; 首字母capitals–>判定第二个字母是否大写–>所有字母大写 otherwise 除第一个以外全部小写&a…

使用xxl-job执行定时任务

文章目录 使用xxl-job执行定时任务xxl-job原理我们自己的项目里面需要怎么写定时任务呢&#xff1f;如果想要使用xxl-job我们需要在服务器上部署两个项目 使用xxl-job执行定时任务 xxl-job原理 首先xxl-job的全拼是“XiaoXiaoLiang Job”或者“Xu Xue Li”作者的名字&#xf…

华清数据结构day4 24-7-19

链表的相关操作 linklist.h #ifndef LINKLIST_H #define LINKLIST_H #include <myhead.h> typedef int datatype; typedef struct Node {union{int len;datatype data;};struct Node *next; } Node, *NodePtr;NodePtr list_create(); NodePtr apply_node(datatype e); …

从零开始学Java(超详细韩顺平老师笔记梳理)06——面向对象编程基础(上):类与对象、成员方法、传参机制、对象克隆、递归(斐波那契、迷宫、汉诺塔、八皇后)

文章目录 前言一、类与对象1. 类与对象的概述2. 快速入门&#xff08;用面向对象的方式解决问题&#xff09;3. 对象在内存中的存在形式&#xff08;重要&#xff09;4. 属性5. 类与对象的内存分配机制 二、成员方法1. 基本介绍2. 快速入门3. 方法调用机制原理&#xff08;重点…

【HarmonyOS学习】用户文件访问

概述 文件所有者为登录到该终端设备的用户&#xff0c;包括用户私有的图片、视频、音频、文档等。 应用对用户文件的创建、访问、删除等行为&#xff0c;需要提前获取用户授权&#xff0c;或由用户操作完成。 用户文件访问框架 是一套提供给开发者访问和管理用户文件的基础框…

【JavaEE初阶】线程的概念及创建

目录 &#x1f4d5; 前言 &#x1f4d5; 认识线程&#xff08;Thread&#xff09; &#x1f6a9; 概念 &#x1f60a;线程是什么 &#x1f642; 为啥要有线程 &#x1f62d; 进程和线程的区别&#xff08;面试题重点&#xff09; &#x1f92d; Java的线程和操作系统线程…

MyBatis-Plus的基本使用(一)

目录 前言 特性 MyBatis-Plus入门案例 常用注解 小结 前言 这篇文章主要来学习MyBatis-Plus这个非常强大的框架. 在学习MyBatis-Plus之前,需要有MyBatis的学习基础.因为MyBatis -Plus 是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#x…

Leetcode3216. 交换后字典序最小的字符串

Every day a Leetcode 题目来源&#xff1a;3216. 交换后字典序最小的字符串 解法1&#xff1a;模拟 找到第一个 s[i] > s[i 1]&#xff0c;且它们奇偶性相同&#xff0c;交换它们。 代码&#xff1a; /** lc appleetcode.cn id3216 langcpp** [3216] 交换后字典序最小…

Efficient and Effective Weakly-Supervised Action Segmentation via ATBA

**基于动作转移感知边界对齐的高效弱监督动作分割**介绍 动作分割的目的是将一个长的未裁剪的视频分割成几个片段&#xff0c;并将每个片段分类为一个动作类别&#xff0c;如下图所示&#xff1a; 弱监督动作分割 现有的训练方法大多需要通过对所有帧和文本进行序列比对来…

JavaScript构造函数小挑战

// 编码挑战 #1 /* 使用构造函数实现一辆汽车。一辆汽车有一个品牌和一个速度属性。speed 属性是汽车当前的速度&#xff0c;单位为 km/h&#xff1b; a. 执行一个 “accelerate ”方法&#xff0c;将汽车的速度提高 10&#xff0c;并将新速度记录到控制台&#xff1b; 3. a.…

笔记小结:现代卷积神经网络之批量归一化

本文为李沐老师《动手学深度学习》笔记小结&#xff0c;用于个人复习并记录学习历程&#xff0c;适用于初学者 训练深层神经网络是十分困难的&#xff0c;特别是在较短的时间内使他们收敛更加棘手。 本节将介绍批量规范化&#xff08;batch normalization&#xff09;&#xf…

Dav_笔记10:Using SQL Plan Management之3

将SQL计划基准与SQL Tuning Advisor一起使用 使用SQL Tuning Advisor调整SQL语句时&#xff0c;如果顾问程序找到调优计划并验证其性能优于从相应SQL计划基准中选择的计划&#xff0c;则建议接受SQL配置文件。 接受SQL配置文件后&#xff0c;数据库会将调整后的计划添加到相应…

群管机器人官网源码

一款非常好看的群管机器人html官网源码 搭建教程&#xff1a; 域名解析绑定 源码文件上传解压 访问域名即可 演示图片&#xff1a; 群管机器人官网源码下载&#xff1a;客户端下载 - 红客网络编程与渗透技术 原文链接&#xff1a; 群管机器人官网源码

云仓如何改变传统仓储模式?

云仓&#xff0c;即云仓储&#xff0c;是一种基于互联网技术的现代仓储模式&#xff0c;与传统的仓储模式相比&#xff0c;它在多个方面进行了创新和优化&#xff0c;包括&#xff1a; ———————————————————— 1、数据管理与实时监控&#xff1a; 云仓储利…

Element-ui :el-table 中表尾合计行

Table 表格 | Element Plus <template><el-table :data"tableData" border show-summary :summary-method"getSummariesss" style"width: 100%"><el-table-column prop"id" label"ID" width"180"…

C++与lua联合编程

C与lua联合编程 一、环境配置二、lua基本语法1.第一个lua和C程序2.基本数据类型和变量2.1 Nil2.2 Booleans2.3 Numbers2.4 String(最常用) 3. 字符串处理3.1 错误处理3.2 字符串长度:string.len3.3 字符串子串 :string.sub3.4 字符串查找: string.find3.5字符串替换: string.gs…

【笔记】ubuntu 误退了搜狗输入法:终端上输入fcitx即可重启

有时候&#xff0c;我们可能嫌弃ubuntu上的搜狗输入法&#xff0c;点击了退出&#xff1a; 但是当我们想开启搜狗输入法时&#xff0c;发现它消失了&#xff0c;此时我们可以打开终端&#xff0c;键入&#xff1a; fcitx 即可成功开启。

一些和颜色相关网站

1.中国传统色 2.网页颜色选择器 3.渐变色网站 4.多风格色卡生成 5.波浪生成 6.半透明磨砂框 7.色卡组合

全国区块链职业技能大赛国赛考题前端功能开发

任务3-1:区块链应用前端功能开发 1.请基于前端系统的开发模板,在登录组件login.js、组件管理文件components.js中添加对应的逻辑代码,实现对前端的角色选择功能,并测试功能完整性,示例页面如下: 具体要求如下: (1)有明确的提示,提示用户选择角色; (2)用户可看…