HTTPServer改进思路2(mudou库核心思想融入)

news2024/11/26 5:30:04

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.coloradmin.cn/o/1941447.html

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

相关文章

完美解决Ubuntu的MySQL临时文件夹修改调整

打开终端,输入以下命令$ sudo -i # 切换root用户 $ systemctl stop mysql.service $ mkdir /home/tmp $ chown root:root /home/tmp $ chmod 1777 /home/tmp $ gedit /etc/mysql/mysql.conf.d/mysqld.cnf以上最后一条命令执行完后,在打开的mysqld.cnf文件做如下修改并保存关闭…

栈和队列(C语言)

栈的定义 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&#xff1a;…

【Python正则表达式】:文本解析与模式匹配

文章目录 1.正则表达式2. re模块3.修饰符3.元字符3-1 字符匹配元字符3-2 重复次数限定元字符3-3 字符集合匹配元字符3-4 分组元字符3-5 边界匹配元字符3-6 字符类别匹配元字符 4.技巧4-1 贪婪与非贪婪 5.案例 1.正则表达式 正则表达式面向什么样的问题&#xff1f; 1、判断一个…

平衡三进制计算机模拟2

1、计算机的起源 在19世纪的时候&#xff0c;“Computer”代表的并不是计算机&#xff0c;而是计算员&#xff0c;那时并没有计算机的概念&#xff0c;而计算员当然是要计算东西的&#xff0c;当时计算东西多&#xff0c;计算水平也参差不齐&#xff0c;加上疲劳等因素&#xf…

华夏银行的进和退:不良率位列同业第一,分红比例常年不达标

撰稿|芋圆 来源|贝多财经 近日&#xff0c;华夏银行股份有限公司&#xff08;SH:600015&#xff0c;下称“华夏银行”&#xff09;北京分行联合北京产权交易所举办了特殊资产推介会。会上&#xff0c;华夏银行包括北京分行在内的7家分行和信用卡中心&#xff0c;共同推介了超…

从操作系统层面认识Linux

描述进程-PCB Linux操作系统下的PCB是: task_struct https://www.cnblogs.com/tongyan2/p/5544887.htmlhttps://www.cnblogs.com/tongyan2/p/5544887.html校招必背操作系统面试题-什么是 PCB&#xff08;进程控制块&#xff09; &#xff1f;_哔哩哔哩_bilibili校招必背操作系…

汉明权重(Hamming Weight)(统计数据中1的个数)VP-SWAR算法

汉明权重&#xff08;Hamming Weight&#xff09;&#xff08;统计数据中1的个数&#xff09;VP-SWAR算法 定义 汉明重量是一串符号中非零符号的个数。它等于同样长度的全零符号串的汉明距离(在信息论中&#xff0c;两个等长字符串之间的汉明距离等于两个字符串对应位置的不同…

浏览器插件利器--allWebPluginV2.0.0.16-beta版发布

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX控件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持Chrome、Firefo…

刷题了:242.有效的字母异位词 |349. 两个数组的交集 | 202. 快乐数|1. 两数之和

学习记录&#xff0c;主要参考&#xff1a;代码随想录 哈希表理论基础 文章讲解:https://programmercarl.com/%E5%93%88%E5%B8%8C%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 哈希表&#xff08;Hash table&#xff09; 哈希表是根据关键码的值而直接进行访问的数据…

deepseek-vl 论文阅读笔记

目录 一、已有模型性能差距分析 二、创新点 数据集构建 模型架构 训练策略 实验与评估 三、细节 数据构建 内部SFT数据的分类体系 模型架构 训练流程包括三个阶段 系统包含三个模块 混合视觉编码器 视觉-语言适配器 语言模型 训练策略 阶段一&#xff1a;训练…

nfs和web服务器的搭建

&#xff08;一&#xff09;web服务器的搭建 1.配置基本环境 要点有&#xff0c;yum源&#xff0c;包含nginx和阿里云&#xff08;或者腾讯云或者华为云&#xff09;&#xff0c;这里的相关知识可以参考之前的yum配置笔记 2.安装nginx yum -y install nginx 3.验证并且开启服…

MLCC电容特性及注意事项

MLCC结构和工作原理 如下图所示&#xff0c;MLCC电容结构较简单&#xff0c;由陶瓷介质、内电极金属层和外电极三层构成。 MLCC的电容量公式可以如下表示&#xff1a; C&#xff1a;电容量&#xff0c;以F&#xff08;法拉&#xff09;为单位&#xff0c;而MLCC之电容值以PF&…

AWE2025正式启动,AWE×AI 推动智慧生活的普及

7月18日&#xff0c;2025年中国家电及消费电子博览会&#xff08;AWE2025&#xff09;正式启动。主办方宣布&#xff0c;AWE2025的主题为“AI科技、AI生活”&#xff0c;展会将于2025年3月20-23日在上海新国际博览中心举办。 作为全球三大家电和消费电子领域展会之一&#xff…

数字孪生智慧农业技术:优化农业生产的未来

随着科技的进步和全球食品需求的增长&#xff0c;数字孪生智慧农业技术作为现代农业生产的新兴力量&#xff0c;正在为农业界带来革命性的变化和巨大的发展潜力。本文将深入探讨数字孪生智慧农业技术的核心架构、关键技术应用及其在提升农业生产效率和可持续发展中的作用。 ###…

word压缩大小怎么弄?这几种方法轻松压缩word文件!

word压缩大小怎么弄&#xff1f;面对庞大无比的Word文档&#xff0c;我们往往遭遇诸多不便&#xff0c;它们如同数据海洋中的巨鲸&#xff0c;不仅鲸吞存储空间&#xff0c;更在传输途中缓缓游弋&#xff0c;耗费大量时光&#xff0c;在资源有限的设备上&#xff0c;这些文档仿…

python基础语法 007 文件操作-1读取写入

1 文件操作 1.1 什么时候用文件操作&#xff1f; 打开文档写东西看东西拿文档做统计 在python 文档操作作用 存储数据读取数据 打开文件有什么用&#xff1f; 读取数据&#xff0c;写入数据不管什么数据都可以用open打开&#xff0c;如可复制一张图片 1.2 open() 读取,…

开源模型应用落地-FastAPI-助力模型交互-进阶篇-中间件(四)

一、前言 FastAPI 的高级用法可以为开发人员带来许多好处。它能帮助实现更复杂的路由逻辑和参数处理&#xff0c;使应用程序能够处理各种不同的请求场景&#xff0c;提高应用程序的灵活性和可扩展性。 在数据验证和转换方面&#xff0c;高级用法提供了更精细和准确的控制&#…

SqlServer: LAG等开窗函数应用

原贴&#xff1a; https://bbs.csdn.net/topics/619167074 https://learn.microsoft.com/zh-cn/sql/t-sql/functions/lag-transact-sql?viewsql-server-ver16 CREATE TABLE #kcb(xlh INT,shul INT,ftshl INT ) INSERT INTO #kcb(xlh,shul,ftshl) SELECT 1,20…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 中文分词模拟器(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…

python基础语法 007 文件操作-2文件支持模式文件的内置函数

1.3 文件支持的模式 模式含义ropen a file for reading(default)wopen a file for writing,creates a new file if it does not exist or truncates the file if it exists x open a file foe exclusive creation. if the file already exists, the operation fails.独创模式&…