muduo库的简化仿写知识要求C11特性多线程智能指针Linux网络通信多路复用为什么写这个项目在学校学了这些知识想要提高自己的能力就在网上找的相关的开源项目通过原码阅读、仿写的⽅式提升多线程⽹络编程能⼒。整体计划1.高性能服务器框架 102.支持应用层协议HTTP 53.通过自定制协议实现RPC通信框架 自定制协议在网络通信中别人不知道我的格式 5框架设计Reactor模型别名反应堆模型直译事件驱动模型原理事件循环模型实现机制。就是epoll核心特性被动反应不像主动轮询而是等待事件发生然后反应链式反应⼀个事件可能触发⼀系列后续处理能量集中少量线程处理大量连接像反应堆高效产⽣能量控制中心像核反应堆的控制系统统⼀调度所有事件传统阻塞模型主动询问每个客户端连接主动询问“你有数据吗”Reactor模型被动反应事件发生时自动被唤醒reactor模型的演化过程单reactor模型优点极其简单缺点一个线程里既要获取新连接又要处理数据单reactor线程池模型把 业务处理 单独拿出来用 线程池 处理。缺点依旧存在单线程IO的性能瓶颈。只有一个线程处理所有网络 IO 事件主从reactor模型主从 Reactor 模型将连接接收与读写事件处理分离主 Reactor 只负责 accept 新连接并分派多个从 Reactor 分担网络 IO 与协议解析耗时业务交由独立业务线程池充分利用多核 CPU、消除单线程瓶颈与单点故障。Proactor模型别名前摄器模型、主动器模型核心思想应用程序发起异步I/O操作然后继续执行其他任务当I/O操作完成时操作系统会通知应用程序应用程序再处理相应的业务逻辑。Reactor当I/O就绪时通知我我来做读写操作Proactor我告诉你我要读写什么你帮我做完后通知我结果。核心特点异步I/O应⽤程序调⽤异步I/O操作由操作系统负责执⾏I/O应⽤程序不阻塞等待。完成通知I/O操作完成后操作系统主动通知应⽤程序。分离关注点应⽤程序的I/O操作和事件处理分离由操作系统负责I/O操作应⽤程序负责业务处 理。I/O操作1.发起IO操作2.等待IO就绪3.拷贝数据4.IO调用返回异步IO进程发起IO调用IO等待数据拷贝过程由系统完成IO完成后通知进程概要设计Reactor模型实现主要分为三⼤模块reactor、handler逻辑整合在这三⼤模块中⼜细分了其他 的⼦模块进⾏细节实现。模块设计reactor负责事件循环监控及分发功能事件监控Poller描述符监控模块负责描述符的事件监控与事件分发。Eventloop事件循环模块负责实现Poller事件循环监控 任务池实现连接的线程安全操作。Weakup事件循环唤醒模块负责Poller的阻塞唤醒事件描述符的读事件处理muduo中没 有LoopThread模块负责实现Eventloop与对应线程thread封装在⼀起。LoopThreadPool模块负责实现池化LoopThread功能handler负责描述符的监控事件描述以及事件处理事件处理Channel事件处理器模块负责描述描述符的监控事件以及事件处理TimerQueue定时器模块负责实现定时器中定时器描述符的读事件处理Timestamp时间操作模块负责简单的系统⽇期时间操作Timer定时任务模块负责描述⼀个定时任务过期时间是否重复过期回调...TimerId模块与定时任务Timer对应的定时任务ID唯⼀序号定时任务指针Acceptor监听对象模块负责监听套接字的读事件处理新连接Connection连接对象模块负责I/O套接字的读写事件处理。IO处理Buffer模块负责实现发送/接收数据缓冲区Sockets模块负责套接字的各项基础操作逻辑整合TcpServer服务器模块负责基于以上模块整合实现服务端TcpClient客⼾端模块负责基于以上模块整合实现客户端模块关系图详细设计channelfd要监控的描述符event要监控的事件revent实际就绪的事件readcallback读事件回调函数writecallback写事件回调函数errorcallback错误时间回调函数closecallback连接关闭事件回调函数功能如果要对哪个描述符进行事件监控就为其构造一个channel对象。这个channel对象就描述了监控了哪个描述符的哪个事件。然后将这些信息交给Pollerepoll进行实际的事件监控。pollerepoll封装updataChannelremoveChannelwaiteventLoopepoll_wait事件监控执行跨线程任务weakuoChannelfdthis构造一个channel对象里面有fdeventloop*loop。eventloop*loop指向的就是eventloop对象。enableReading开始监控调用loop-updateChannelthis指向eventloop的updateChannel。然后把updateChannel加到poller里面进行监控。是事件循环类。功能1.针对Poller进行二次封装实现channel的事件监控。2.解决后期连接 线程安全问题 ——任务池。3.定时任务的操作。定时器的设计Timestamp类时间戳管理类Timerld定时任务ID。唯一标识一个定时任务对象Timer类定时任务类封装了一个回调函数对象TimerQueue类定时任务管理类定时器实现原理1.能够让系统通知进程自身现在超时了。告诉系统一个固定的时间点让系统在这个时间点通知进程timerfd本质原理本质是内核的一个8B计数器计时功能当我们给描述符设置了一个超时/间隔时间内核在每隔一定的间隔时间后给这个计数器1这时候定时器描述符就会触发可读事件这个事件就是超时通知超时之后我们需要将计数器中的计数归零。2.能够快速的找出超时任务针对这些任务执行一下定时任务管理 实现思想1.时间轮思想1.定义一个时间轮环形数组/链表每个结点都是一个链表该链表中存放的都是定时任务2.定义一个刻度指针刻度指针指向哪个结点那个结点链表中的任务就都是过期任务3.通过定时器让刻度指针移动起来优点不用调整堆结构缺点需要不断触发事件2.小根堆思想小根堆根顶总是最小节点定义一个以时间为比较关键字的小根堆堆顶任务就是最接近超时任务。实现过程1.获取堆顶节点的时间戳定时定时器超时时间2.当定时器超时的时候意味着堆顶节点必然超时3.当超时时不断从堆顶取出节点直到堆顶节点时间大于当前系统时间没有超时优点不会出现空跑muduo库中的定时器的实现小根堆思想。实现所用的数据结构红黑树节点结构pairtimestamp , timer左叶子节点就是最接近超时的节点。定时器的实现1.使用timerfd实现定时器超时通知2.使用红黑树进行超市任务管理mappairtimestamp , timer*在收到超时通知后快速获取过期任务。3.实现细节1.定义一个定时任务池保存所有的定时任务。2.取出任务池中最小节点的超时时间设置为定时器的国企通知时间3.当收到通知则从定时任务池中取出所有的过期任务然后进行处理。4.针对所有的过期任务判断是否是循环任务如果是且没有被标记为取消则重新添加到定时任务池中如果时但是被标记为取消则直接释放任务如果不是则直接释放任务。取消定时任务的细节1如果任务在定时任务池中意味着必然不是正在执行的过期任务。2如果任务不在定时任务池中这个任务必然在过期池中正在被执行为什么要有定时器1.几乎在所有的网络通信库中都会配备有定时器功能因为很多时候我们搭建了服务器都需要丢客户端连接设置超时断开时间。2.任务池加入的任务是什么任务就是一个回调函数对象任务管理信息3.循环任务都可能存放在哪些池子中1任务都在红黑树定时任务池中2任务过期的时候会从定时任务池中取出放到临时的过期池中处理处理完毕后重新放回定时任务池。Acceptor监听事件的处理TcpConnection通信事件的处理readv分块接收操作核心关键点:为什么muduo库性能在大块数据的pingpong测试中比libevent高了近3倍因为muduo中使用readv分块接收一次IO取出了socket缓冲区所有数据;而libevent是循环每次接收4096字节数据。核心关键点:muduo库中epoll监控时事件触发模式使用的是水平触发而不是边缘触发。水平触发:只要socket接收缓冲区中的数据大于高水位标记(1B)就会触发事件边缘触发:只有新数据到来的时候才会触发事件强制要求程序员在一次事件触发中处理完所有数据减少了数据触发数量。因为muduo数据接受操作使用分块接收一次性就取出了所有数据没必要使用边缘触发。水平出发逻辑也更加简单。逻辑关系fd挂载到epoll找到Channel里的事件的回调函数然后执行。Acceptor监听管理器里有个handleRead来获取新连接。Channel里的回调函数就是handleRead。获取到的新连接会创建一个TcpConnection里面封装一个Channel对象来设置一系列的回调函数。TimerQueue里有个定时器描述符也会封装一个Channel对象执行定时任务。请求流程1.服务器启动Main Reactor 开始监听端口。2.客户端发起连接Acceptor 读取事件accept 得到新 fd。3.Main Reactor 轮询选择一个 Sub Reactor。4.创建 TcpConnection 对象绑定到对应 Sub Reactor。5.数据到达时epoll 通知Channel 调用读回调。6.数据读到 Buffer触发用户的 MessageCallback。7.用户 send 数据时先写入输出缓冲区开启写事件可写时自动发送。8.连接关闭时自动清理资源、回调、移除监听。
基于主从Reactor模型的高性能网络通信框架
muduo库的简化仿写知识要求C11特性多线程智能指针Linux网络通信多路复用为什么写这个项目在学校学了这些知识想要提高自己的能力就在网上找的相关的开源项目通过原码阅读、仿写的⽅式提升多线程⽹络编程能⼒。整体计划1.高性能服务器框架 102.支持应用层协议HTTP 53.通过自定制协议实现RPC通信框架 自定制协议在网络通信中别人不知道我的格式 5框架设计Reactor模型别名反应堆模型直译事件驱动模型原理事件循环模型实现机制。就是epoll核心特性被动反应不像主动轮询而是等待事件发生然后反应链式反应⼀个事件可能触发⼀系列后续处理能量集中少量线程处理大量连接像反应堆高效产⽣能量控制中心像核反应堆的控制系统统⼀调度所有事件传统阻塞模型主动询问每个客户端连接主动询问“你有数据吗”Reactor模型被动反应事件发生时自动被唤醒reactor模型的演化过程单reactor模型优点极其简单缺点一个线程里既要获取新连接又要处理数据单reactor线程池模型把 业务处理 单独拿出来用 线程池 处理。缺点依旧存在单线程IO的性能瓶颈。只有一个线程处理所有网络 IO 事件主从reactor模型主从 Reactor 模型将连接接收与读写事件处理分离主 Reactor 只负责 accept 新连接并分派多个从 Reactor 分担网络 IO 与协议解析耗时业务交由独立业务线程池充分利用多核 CPU、消除单线程瓶颈与单点故障。Proactor模型别名前摄器模型、主动器模型核心思想应用程序发起异步I/O操作然后继续执行其他任务当I/O操作完成时操作系统会通知应用程序应用程序再处理相应的业务逻辑。Reactor当I/O就绪时通知我我来做读写操作Proactor我告诉你我要读写什么你帮我做完后通知我结果。核心特点异步I/O应⽤程序调⽤异步I/O操作由操作系统负责执⾏I/O应⽤程序不阻塞等待。完成通知I/O操作完成后操作系统主动通知应⽤程序。分离关注点应⽤程序的I/O操作和事件处理分离由操作系统负责I/O操作应⽤程序负责业务处 理。I/O操作1.发起IO操作2.等待IO就绪3.拷贝数据4.IO调用返回异步IO进程发起IO调用IO等待数据拷贝过程由系统完成IO完成后通知进程概要设计Reactor模型实现主要分为三⼤模块reactor、handler逻辑整合在这三⼤模块中⼜细分了其他 的⼦模块进⾏细节实现。模块设计reactor负责事件循环监控及分发功能事件监控Poller描述符监控模块负责描述符的事件监控与事件分发。Eventloop事件循环模块负责实现Poller事件循环监控 任务池实现连接的线程安全操作。Weakup事件循环唤醒模块负责Poller的阻塞唤醒事件描述符的读事件处理muduo中没 有LoopThread模块负责实现Eventloop与对应线程thread封装在⼀起。LoopThreadPool模块负责实现池化LoopThread功能handler负责描述符的监控事件描述以及事件处理事件处理Channel事件处理器模块负责描述描述符的监控事件以及事件处理TimerQueue定时器模块负责实现定时器中定时器描述符的读事件处理Timestamp时间操作模块负责简单的系统⽇期时间操作Timer定时任务模块负责描述⼀个定时任务过期时间是否重复过期回调...TimerId模块与定时任务Timer对应的定时任务ID唯⼀序号定时任务指针Acceptor监听对象模块负责监听套接字的读事件处理新连接Connection连接对象模块负责I/O套接字的读写事件处理。IO处理Buffer模块负责实现发送/接收数据缓冲区Sockets模块负责套接字的各项基础操作逻辑整合TcpServer服务器模块负责基于以上模块整合实现服务端TcpClient客⼾端模块负责基于以上模块整合实现客户端模块关系图详细设计channelfd要监控的描述符event要监控的事件revent实际就绪的事件readcallback读事件回调函数writecallback写事件回调函数errorcallback错误时间回调函数closecallback连接关闭事件回调函数功能如果要对哪个描述符进行事件监控就为其构造一个channel对象。这个channel对象就描述了监控了哪个描述符的哪个事件。然后将这些信息交给Pollerepoll进行实际的事件监控。pollerepoll封装updataChannelremoveChannelwaiteventLoopepoll_wait事件监控执行跨线程任务weakuoChannelfdthis构造一个channel对象里面有fdeventloop*loop。eventloop*loop指向的就是eventloop对象。enableReading开始监控调用loop-updateChannelthis指向eventloop的updateChannel。然后把updateChannel加到poller里面进行监控。是事件循环类。功能1.针对Poller进行二次封装实现channel的事件监控。2.解决后期连接 线程安全问题 ——任务池。3.定时任务的操作。定时器的设计Timestamp类时间戳管理类Timerld定时任务ID。唯一标识一个定时任务对象Timer类定时任务类封装了一个回调函数对象TimerQueue类定时任务管理类定时器实现原理1.能够让系统通知进程自身现在超时了。告诉系统一个固定的时间点让系统在这个时间点通知进程timerfd本质原理本质是内核的一个8B计数器计时功能当我们给描述符设置了一个超时/间隔时间内核在每隔一定的间隔时间后给这个计数器1这时候定时器描述符就会触发可读事件这个事件就是超时通知超时之后我们需要将计数器中的计数归零。2.能够快速的找出超时任务针对这些任务执行一下定时任务管理 实现思想1.时间轮思想1.定义一个时间轮环形数组/链表每个结点都是一个链表该链表中存放的都是定时任务2.定义一个刻度指针刻度指针指向哪个结点那个结点链表中的任务就都是过期任务3.通过定时器让刻度指针移动起来优点不用调整堆结构缺点需要不断触发事件2.小根堆思想小根堆根顶总是最小节点定义一个以时间为比较关键字的小根堆堆顶任务就是最接近超时任务。实现过程1.获取堆顶节点的时间戳定时定时器超时时间2.当定时器超时的时候意味着堆顶节点必然超时3.当超时时不断从堆顶取出节点直到堆顶节点时间大于当前系统时间没有超时优点不会出现空跑muduo库中的定时器的实现小根堆思想。实现所用的数据结构红黑树节点结构pairtimestamp , timer左叶子节点就是最接近超时的节点。定时器的实现1.使用timerfd实现定时器超时通知2.使用红黑树进行超市任务管理mappairtimestamp , timer*在收到超时通知后快速获取过期任务。3.实现细节1.定义一个定时任务池保存所有的定时任务。2.取出任务池中最小节点的超时时间设置为定时器的国企通知时间3.当收到通知则从定时任务池中取出所有的过期任务然后进行处理。4.针对所有的过期任务判断是否是循环任务如果是且没有被标记为取消则重新添加到定时任务池中如果时但是被标记为取消则直接释放任务如果不是则直接释放任务。取消定时任务的细节1如果任务在定时任务池中意味着必然不是正在执行的过期任务。2如果任务不在定时任务池中这个任务必然在过期池中正在被执行为什么要有定时器1.几乎在所有的网络通信库中都会配备有定时器功能因为很多时候我们搭建了服务器都需要丢客户端连接设置超时断开时间。2.任务池加入的任务是什么任务就是一个回调函数对象任务管理信息3.循环任务都可能存放在哪些池子中1任务都在红黑树定时任务池中2任务过期的时候会从定时任务池中取出放到临时的过期池中处理处理完毕后重新放回定时任务池。Acceptor监听事件的处理TcpConnection通信事件的处理readv分块接收操作核心关键点:为什么muduo库性能在大块数据的pingpong测试中比libevent高了近3倍因为muduo中使用readv分块接收一次IO取出了socket缓冲区所有数据;而libevent是循环每次接收4096字节数据。核心关键点:muduo库中epoll监控时事件触发模式使用的是水平触发而不是边缘触发。水平触发:只要socket接收缓冲区中的数据大于高水位标记(1B)就会触发事件边缘触发:只有新数据到来的时候才会触发事件强制要求程序员在一次事件触发中处理完所有数据减少了数据触发数量。因为muduo数据接受操作使用分块接收一次性就取出了所有数据没必要使用边缘触发。水平出发逻辑也更加简单。逻辑关系fd挂载到epoll找到Channel里的事件的回调函数然后执行。Acceptor监听管理器里有个handleRead来获取新连接。Channel里的回调函数就是handleRead。获取到的新连接会创建一个TcpConnection里面封装一个Channel对象来设置一系列的回调函数。TimerQueue里有个定时器描述符也会封装一个Channel对象执行定时任务。请求流程1.服务器启动Main Reactor 开始监听端口。2.客户端发起连接Acceptor 读取事件accept 得到新 fd。3.Main Reactor 轮询选择一个 Sub Reactor。4.创建 TcpConnection 对象绑定到对应 Sub Reactor。5.数据到达时epoll 通知Channel 调用读回调。6.数据读到 Buffer触发用户的 MessageCallback。7.用户 send 数据时先写入输出缓冲区开启写事件可写时自动发送。8.连接关闭时自动清理资源、回调、移除监听。