【Mudo库】实战项目之简要介绍

news2024/11/16 19:10:49

文章目录

  • 前言
  • 一、效果演示
  • 二、模块
    • 1. 介绍
    • 2. 服务器模块
    • 3. 应用层模块
  • 尾序

前言

 各位C友们,好久不见,最近一个月在搞项目,算是半摆半学的状态吧,博客断更了一段时间,现在项目搞完了,博客之后也会慢慢更新的,最近的几篇文章会将最近一个月写的项目总结出来分享给大家,希望对大家有所帮助!话不多说,先来对项目做一个简要的总结,即对系统的接口使用C++进行再度封装,实现一个高并发服务器的组件,用户可以根据切换具体的应用层协议和快速搭建服务器。下文进行项目的详细介绍。

一、效果演示

说明:效果是基于Http协议搭建的服务器的主页和错误界面的响应,只是为了简单的验证项目能否正常的运作,并不能说明服务器的性能,在项目最后的测试部分,将会进行压力测试,看所搭建服务器的性能如何。

主页

在这里插入图片描述

错误

在这里插入图片描述

 经过如上实验可以简单的得出,所编写的最终服务器还是没有大毛病的,可以进行正常的文件读写。至于其它的实际的功能性接口,即一些网站实际业务的处理接口,不在此项目的能力范围之内。如要进行验证,则要搭建对应的前端的服务并实现后端的处理接口,有兴趣的同学可根据需要自行实现并验证。

二、模块

1. 介绍

  • 命令
find . \( -name "*.cc" -o -name "*.h" -o -name "*.hpp" \) -type f -exec wc -l {} +

使用此命令,查看一下本项目的总代码量大概在3500行左右,总的来说还是有不少的代码的,但也可以学习到不少的技术。
在这里插入图片描述

2. 服务器模块

本模块将从对连接和处理两个角度进行简要介绍,具体的实现还要落实到代码实现部分,连接主要是对系统的接口使用C++进行封装成类,便于上层进行调用;处理是通过多线程进行实现的,主要采用的是主从Reactor模式实现,即将连接的监听和初始化放在主Reactor中,而连接的处理操作则放在其它的Reactor中,从而提升服务器的性能。

关于连接实现的子模块:

套接字,关于连接的套接字

图解:
在这里插入图片描述

  • 网络套接字,即文件描述符,根据不同的用途可分为客户端发起连接的套接字,服务端用于监听的套接字,以及从全连接队列中拿上来的套接字三种,根据不同的需要此处对套接字运用继承的思想,进一步的具象化实现,方便进行使用。
  • 服务端监听套接字,继承普通套接字的功能外,还需要进行对连接的绑定,监听,接收功能。
  • 服务端接收套接字,只需要接收服务端通过监听获取接收的套接字,从而进行业务的处理
  • 客户端套接字,除基本的接收和发送数据爱,还需额外实现对服务端发送建立连接的请求。

连接事件的监听模块,即对epoll系列接口的封装

图解:
在这里插入图片描述

  • Linux操作系统内核中,对套接字事件的管理已经有成熟的epoll系列的接口供我们使用,我们只需对现成的接口进行再度封装,更加简便的使用即可,除此之外如果对这一部分有疑惑的,可见博主之前写的一篇文章:【Linux进阶之路】高级IO,里面系统的介绍了IO模型。
  • 构造函数,将会调用epoll_create创建epoll_fd用于管理就绪和监听事件,内核中采用的是红黑树进行的管理。
  • 事件的更新,涉及三个部分,即事件的添加,修改,删除,涉及三个选项,EPOLL_CTL_ADD,EPOLL_CTL_MOD,EPOLL_CTL_DEL,是对内核结构struct epoll_event的修改。
  • 事件的添加和删除,除了对内核结构的修改外,还要对哈希表中的结构,即用户对事件的监控的结构,进行修改。
  • 事件的等待,即阻塞等待就绪的文件描述符,然后方便对其执行业务处理。

连接事件的处理模块,即对就绪事件设置回调函数

图解:
在这里插入图片描述

  • 总的来说,主要是读,写,刷新,错误四种事件的设置,取消,打开和处理,事件的更新和移除操作,事件属性信息的获取。
  • 回调函数的设置是在连接初始化时进行的,取消是在连接异常或者关闭时进行的。刷新回调与项目的非活跃销毁有关(之后会提及),错误回调指的是对连接进行释放操作。
  • 就绪事件的设置是在Poller的Wait接口进行设置的,处理是在多线程中的任务池执行的,根据就绪和监控事件进行执行对应的回调方法。
  • 监控事件的打开是在连接初始化完毕进行打开的,关闭是在连接异常或者不需要关心时进行。
  • 更新和移除事件,指的是通过调用Poller中的更新和移除的接口进行实现的,此处只做简要介绍即可。

连接事件的监听模块,即对连接进行监听和接收

图解:
在这里插入图片描述

  • Acceptor模块是对监听套接字SSocket的进一步封装,在构造完成对套接字的初始化,绑定,监听;设置连接处理回调函数。
  • SSocket在构造函数自动完成绑定与监听工作,通过Channel来完成读事件的处理和监控,Channel会调用Poller中的UpDate进行监控。
  • 连接处理回调的设置,回调函数由服务器Server对象进行设置,主要完成的是对连接初始化工作,设置完即可启动读监控获取连接了。

连接事件的定时模块,即设置定时任务以及非活跃销毁连接

图解1:

在这里插入图片描述

  • TimerWheel主要完成定时任务的添加,刷新,取消,管理功能。主要采用时间轮和timer_fd文件描述符,智能指针的技术进行实现。
  • 初始化工作主要完成timerfd的创建,时间轮的初始化,使用Channe设置与打开读回调,监控与执行timerfd的读事件。
  • 定时任务的刷新在被Channel管理连接事件就绪执行,添加则是将定时任务的信息添加到vector和unordered_map中,取消则是调用定时任务(TimerTask)的取消定时销毁接口或者从unordered_map移除定时任务对象。

图解2:
在这里插入图片描述

  • TimerTask则是对定时任务的设置,执行,取消,资源销毁,对定时任务属性信息的管理,辅助TimerWheel的实现。
  • 初始化功能主要是通过TimerWheel进行添加时用来设置对应任务的属性信息,和回调函数。
  • TimerTask实际上由shared_ptr进行管理,并当TimerWheel刷新其引用计数为0时调用析构执行定时任务和资源销毁。
  • 设置资源销毁,其实就是从TimerWheel的unordered_map中移除对应的管理信息。

连接事件的存储模块,即缓存区,一个连接有一对缓存区,即读缓冲区和写缓存区,读缓存区存放客户端发来的数据,写缓存区存放服务器处理后的信息,用于对客户端进行响应。

图解:
在这里插入图片描述

  • Buffer的设计思想是采用双指针或者叫滑动窗口更为合适,即vector容器的下标[读偏移,写偏移) 的中间存放着可读数据块,在读写过程中读偏移和写偏移会动态的移动,因此叫滑动窗口更为贴切。其它的接口都是根据此实现的,在后续文章的实现代码即可深刻体会。

连接事件的上下文模块,因为服务器可能采用的应用层协议使用是不同的上下文,因此使用的是任意类,即一个可以存放任意元素的类进行实现,方便应用层丝滑地切换协议。

图解:
在这里插入图片描述

  • Any类的设计思想还是很值得学习的,即如何设计一个类存放任意元素(内置和自定义类),上述主要是通过内置父类,以及模版子类,Any通过存放一个指向父类指针的成员变量实现,总的来说将内置类,多态,继承运用的十分巧妙,Any外部采用模版取值函数,构造进行获取和初始化进行再度封装。

连接事件的管理模块,整合之前的存储模块,上下文模块,定时模块完成对连接的统一处理

图解:
在这里插入图片描述

  • Connection算的上一个比较综合的模块了,起的 “承上启下” 的作用,即向上为用户提供消息处理,任意事件,初始化连接,上下文的记录回调,及其设置和切换。向下整合Buffer,TimeWheel,Any模块,从而完善连接的功能。

  • 从回调来看,用户只需要关心消息是如何处理的,并不需要关心如何将消息读取和发送;连接的初始化工作,也需要通过用户来完成,比如说上下文的类型就需要通过设置Any类来完成;上下文记录和任意事件处理,用户可关心可不关心。

  • 从读写来看,读取数据需要一个缓存区将数据从内核的缓存区中读取出来,便于之后的数据接收,写数据则是将数据快速的发送,并当内核的发送缓冲区

  • 从上下文来看,设置上下文是通过连接初始化时进行调用的,而切换则是将用户的回调进行全部的切换,进而切换应用层协议。

  • 从非活跃来看,即在TimerWheel中添加一个定时销毁连接的任务,当连接有事件就绪时就进行刷新,直到超过指定时间内没有事件就绪进行销毁处理,从而释放一些服务器资源,避免闲置资源。


关于事件处理实现的子模块:

连接事件的线程与任务模块,使用多线程,完成对连接处理任务的分配,使用任务池完成对连接的处理等功能。

图解:

在这里插入图片描述

  • 此模型主要采用的是Reactor中的主从模式进行实现,即一个线程,通常为主线程完成对连接的监听和初始化,而对于连接的处理工作,则交由线程池中的线程来完成,其中每一个线程绑定一个EventLoop,拥有自己的任务池,用于执行任务。这样连接的接收和处理进行解耦,增加了任务执行效率。
  • 从LoopThread看,创建线程对象,并绑定自定义实现的入口函数,入口函数创建并绑定EventLoop,并开启事件循环。
  • 从LoopThreadPool看,创建出一定数量的线程,并用容器存储对应的LoopThread对象和EventLoop对象的地址,用于给连接分配线程。
  • 从EventLoop看,主要功能是通过Poller对象,即事件监控对象完成对就绪事件的获取,再通过事件对应的Channel对象将就绪任务统一放到任务池中,最后统一执行任务池中的所有任务。同时可以通过添加定时任务完成对Connection的非活跃销毁功能。而互斥锁则是为了保证异常状态下任务池的同步执行。

综合所有模块的服务器模块,即整合连接的实现和处理两大模块中的所有模块向上提供的封装模块。

图解:
在这里插入图片描述

  • TcpServer模块主要连接的监听,分配,管理的功能,即子线程完成对连接的处理工作,主线程完成对连接的监听和初始化工作,包括对创建Connection连接管理对象,分配事件循环,设置回调等,通过哈希表完成对连接的管理和查询功能;

此处整合前面的模块的,画出线程关于连接分配和处理的流程:
在这里插入图片描述

3. 应用层模块

连接的处理和分配的关于服务器性能方面的事情已经介绍完毕了,下面介绍一下本项目采用的上层的应用层协议——Http协议及其相关的功能模块。

应用层协议的功能模块,由于Http协议的报文的分析的是对字符串解析的工作,以及在进行业务处理的过程中可能会从服务器获取文件,因此关于这些功能的接口将被放在此模块当中。

图解:

在这里插入图片描述

应用层协议的解析模块,网络的协议格式一般都是报头 + 报文的形式,Http的协议的请求大致组成为请求行 + 消息头 + 消息体,响应的组成为状态行 + 消息头 + 消息体。通过对信息解析成一些变量,或者放到特定的数据结构中,便可方便进行获取和管理。

请求模块——
在这里插入图片描述
响应模块——
在这里插入图片描述
上下文模块——

在这里插入图片描述

  • 通过HttpContext完成对请求的解析并将结果存放在HttpRequest中,通过服务器的业务处理,完成对HttpRespond的填充,最后通过对HttpRespond的组装完成对客户端的应答。

应用层协议的服务器模块,主要是根据之前的服务器模块和当前模块的请求方法,针对的进行业务处理,最终将响应返回给客户端。

图解:
在这里插入图片描述

  • HttpServer主要包含初始化,更新动态业务处理函数,消息处理三大功能,详细涉及到之前的HttpContext,HttpResponse,Connection,Buffer等模块。
  • 初始化主要是通过TcpServer完成对消息处理函数以及对连接初始化时对上下文的绑定,启动非活跃销毁连接的功能,以及设置静态处理时获取文件的资源路径。
  • 更新动态业务处理函数,主要是通过请求方法,字符串,函数指针回调,将相应的处理方法设置到哈希表当中,便于在客户端进行请求时查找对应的处理方法,以及动态地进行更新和删除。
  • 消息处理,主要涉及获取上下文,即HttpContext接着上一回没有处理完毕的情况接着处理,如果获取到了完整的上下文,就进行业务处理,否则就进行错误页面的填充,最后组织Http协议正文响应发送给客户端。

尾序

本项目基本的功能就介绍完毕了,主要包含服务器和应用层两大模块,详细的子模块上述内容都有图解,希望对大家有所帮助,若有误请在评论区详细说明,我是舜华,期待与你的下一次相遇!

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

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

相关文章

机器学习周报(8.12-8.18)

文章目录 摘要Abstract1.Transformer的结构1.1 序列到序列(Seq2seq)的模型1.2 Transformer 结构1.2.1 Transformer 编码器(Encoder)1.2.2 Transformer解码器(Decoder)1.2.3 编码器-解码器注意力&#xff08…

Java语言程序设计——篇十四(2)

🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿 欢迎大家:这里是我的学习笔记、总结知识的地方,喜欢的话请三连,有问题可以私信🌳🌳&…

c++11(二)

一、右值引用 1、区分左值和右值 语法定义,左值可以取地址,右值无法取地址(右值肯定有地址,但是为了和左值区分,语法上不让取地址) 左值:一个表示数据的表达式(变量名或解引用指针…

如何配置ESXI主机的IP地址管理

🏡作者主页:点击! 🐧Linux基础知识(初学):点击! 🐧Linux高级管理防护和群集专栏:点击! 🔐Linux中firewalld防火墙:点击! ⏰️创作…

通过python脚本查询自己阿里云账号里的某个域名的A记录解析情况,以及测拨,用于排查未使用的解析

安装sdk pip install aliyun-python-sdk-alidns代码全文 import json import requests from aliyunsdkcore.client import AcsClient from aliyunsdkalidns.request.v20150109 import DescribeDomainRecordsRequest# 替换为你的阿里云 AccessKey ID 和 AccessKey Secret acce…

栈与队列 - 逆波兰表达式求值

150. 逆波兰表达式求值 方法一:栈 /*** param {string[]} tokens* return {number}*/ var evalRPN function(tokens) {const stack [];for (const token of tokens) {if (isNaN(Number(token))) { // 非数字const n2 stack.pop(); // 出栈两个数字const n1 s…

假期作业--数据结构

1、顺序表实现学生管理系统(参照顺序表技能)写出菜单界面switch选择,功能1创建顺序表(堆区),2录入学生信息,3插入一个学生信息,4删除一个学生信息,5按照位置修改一个学生…

javaEE中自定义注解以及注解的解析

注解: 就是java代码里的特殊标记,比如Override、Test,作用是:让其它程序根据注解信息来决定怎么执行程序。 自定义注解:自己定义注解 Public interface 注解名称{ Public 属性类型 属性名() default 默认…

写字楼/办公室为什么要建设智慧公厕?有哪些价值?@卓振思众

智慧公厕是指利用先进技术和设备对公共厕所进行智能化管理的系统。这些技术包括物联网(IoT)、传感器技术、大数据分析和自动化系统等。【卓振思众】智慧公厕不仅提升了公厕的使用体验,还实现了更高效的管理和维护。 写字楼/办公室智慧公厕的定…

揭秘RAG与大模型对接:深入探讨9大隐藏挑战

前一段时间,各个大模型在争斗:谁能携带更长、更大的上下文 Prompt,比如 Kimi 说 200 万字,阿里通义千问又说自己能达 1000 万字;大家都知道 Prompt 很重要,但是 RAG 和 长的上下文文本携带 是两个不同的技术…

mac查看jdk安装目录

打开终端,直接输入命令: /usr/libexec/java_home终端即会输出jdk的安装目录:

8.17日学习打卡---Spring Cloud Alibaba(四)

8.17日学习打卡 目录: 8.17日学习打卡分布式流量防护什么是服务雪崩解决方案内部异常治理外部流量控制 SentinelSentinel 基本概念Sentinel 的主要特性Sentinel 是如何工作的Sentinel 与 Hystrix、resilience4j 的对比安装Sentinel控制台将应用接入Sentinel流量控制…

python使用flask实现自动根据url寻找对应目录/文件/方法,实现动态路由

例如访问:/user/index/index_config 则自动访问/user 目录里 index.py文件里的 index_config 方法 实现代码 from flask import Flask,jsonifyapp Flask(__name__)def reg_func(code, data, msg, debugNone, showFalse):return jsonify({code: code,data: data,msg: msg,time…

iPhone照片怎么导入电脑?一键导入毫不费力

随着智能手机的普及,我们越来越依赖手机来记录生活的点点滴滴。iPhone作为其中的佼佼者,其高质量的摄像头为用户捕捉了无数珍贵瞬间。然而,随着照片数量的增多,手机存储空间可能会变得捉襟见肘,此时将照片导入电脑既能…

UniAD_面向规划的自动驾驶

Planning-oriented Autonomous Driving 面向规划的自动驾驶 https://github.com/OpenDriveLab/UniAD Abstract Modern autonomous driving system is characterized as modular tasks in sequential order, i.e., perception, prediction, and planning. In order to perfor…

Python 如何创建和管理虚拟环境?

Python虚拟环境是一个独立的运行环境,能够与系统的全局Python环境相隔离。它允许你在不影响系统其他项目的前提下,为每个项目创建独立的Python环境,并在该环境中安装特定版本的包和依赖项。这在开发多个项目时非常有用,尤其是当这…

EmguCV学习笔记 VB.Net 4.1 颜色变换

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 教程VB.net版本请访问:EmguCV学习笔记 VB.Net 目录-CSDN博客 教程C#版本请访问:EmguCV学习笔记 C# 目录-CSD…

使用Python实现B站自动答题机器人

文章目录 1. 写在前面2. 接口分析3. 点选验证分析4. Python程序实现 【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长…

解密Linux中的通用块层:加速存储系统,提升系统性能

通用块层 通用块层是Linux中的一个重要组件,用于管理不同块设备的统一接口,减少不同块设备的差异带来的影响。它位于文件系统和磁盘驱动之间,类似于Java中的适配器模式,让我们无需关注底层实现,只需提供固定接口即可。…

【13】即时编译(JIT)

概念 即时编译是用来提升应用运行效率的技术。代码会先在JVM上解释执行,之后反复执行的热点代码会被即时翻译成为机器码,直接运行在底层硬件上。 分层编译模式 HotSpot包含多个即时编译器:C1、C2和Graal(Java 10,实验…