• 重写muduo网络库:各模块交互流程梳理总结


    各模块交互流程梳理总结

    先来看整体结构:
    在这里插入图片描述
    图中mainReactor就是TcpServer中的baseLoop_,专门处理listenfd;subReactor就是在start()执行时通过EventLoopThreadPool中的numThreads_线程数量,开辟对应的subLoop,主要处理connfd的读写和关闭事件。
    当subLoop读事件发生时,网络上的数据已经由muduo库帮我们读到缓冲区;发送数据只需把数据写入缓冲区,网络数据的发送交给muduo库来做。而decode、compute、encode等的业务逻辑操作是用户设置的回调OnMessage中处理。

    各模块主要成员

    Channel的主要成员

    在这里插入图片描述
    打包了poller监听的对象fd_、fd感兴趣的事件events_和poller返回发生的具体事件revents_,还有一组事件的回调。events_就是事先设置fd所感兴趣的事件,revents_就是poller返回给channel具体发生的事件,根据具体的事件来执行相应的回调。

    Poller的主要成员

    Poller抽象预留的成员和接口:
    在这里插入图片描述
    Poller和EventLoop是一一对应的关系,ownerLoop_记录了Poller对应的EventLoop,map表channels_的key是fd,value是fd所属的Channel,记录了Poller中的fd和其对应的Channel,用于调试
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    epoll_wait返回具体发生的channel可以通过向Epoll对象添加的event得到,因为注册的时候epool_data_t不是用默认的fd,而是channel*,可以通过返回的epoll_event得到channel*来获取发生事件的fd,map表只是调试用。

    EventLoop

    EventLoop是muduo网络库Reactor模型的核心,相当于Reactor模型中的Reactor反应堆,是事件处理流程的载体,也是Channel和Poller间的桥梁。Channel有两种封装方式:一是Acceptor,二是TcpConnection,两者都依赖于EventLoop。
    Channel没有和Poller关联,那Channel怎么把Channel注册到Poller上或者从Poller移除呢?就是通过EventLoop把他们关联起来。
    在这里插入图片描述
    EventLoop上维护了一个activeChannels_列表,这个列表就是通过Poller来填充的。
    在这里插入图片描述
    EventLoop执行poll也就是epoll_wait调用时把activeChannels_传给了Poller,poll事件发生返回后会填充这个列表,EventLoop通过遍历这个列表通知Channel处理相应的事件。

    EventThreadPool

    EventThreadPool成员及接口
    在这里插入图片描述
    查看它的成员和接口,负责的工作主要负责初始化并启动subLoop,还有决定connfd打包成的Channel的分配策略,仅此而已。getNextLoop()获取下个接收Channel的subLoop,baseLoop_记录mainLoop,loops_记录所有的subLoop。

    Acceptor

    Acceptor成员及接口:
    在这里插入图片描述
    Acceptor和Channel是包含的关系,它处理的事件很单一,只负责新连接的处理,所以它的Channel的事件发生时一定会做accept,除非发生错误。
    Acceptor封装了listenfd的相关操作,主要是bind,listen和accept。bind在Acceptor构造时发生,listen在TcpServer.start()时调用,accept在listenfd的事件回调handleRead中执行。

    TcpConnection

    在这里插入图片描述
    TcpConnection和Channel也是包含的关系,一个连接成功的客户端对应一个TcpConnection,所有的TcpConnection都在subLoop中监听,负责客户端的读写和关闭事件,所以它的Channel发生读事件时,回调一定会往接收缓冲区写数据;发生写事件时一定会往发送缓冲区写数据;发生连接断开事件一定会有close(fd)的操作。

    TcpServer

    TcpServer的成员:
    在这里插入图片描述
    TcpServer就相当于Reactor的起点入口,和Reactor的关系就相当于我们的程序和main()函数一样。它的工作就是负则给整个Reactor做初始化,为mainLoop的事件循环做准备工作。
    它的成员包含了mainLoop,mainLoop监听的Acceptor,subLoop线程池启动对象,保存所有客户端连接以及用户注册的回调。

    启动

    首先就是TcpServer的构造,会产生一个mainLoop,mainLoop对应Poller注册了负责监听新连接的Acceptor,并绑定了handleRead回调。
    然后TcpServer.start(),启动并开启设置线程个数的subLoop,假设是2个,并往subLoop对应的Poller各注册了一个eventfd包装成的wakeupChannel,并绑定了handleRead回调。
    在这里插入图片描述

    新连接和读写、关闭事件

    当mainLoop启动后,有客户端连接,就会触发Acceptor的handleRead回调。handleRead回调会accept得到一个connfd,然后getNextLoop获取connfd所属的subLoop,把connfd打包成channel,并绑定用户设置的回调,然后往这个subLoop的wakeupChannel写一个字节。
    在这里插入图片描述
    subLoop监听到wakeupChannel发生事件就会触发handleRead回调,把包装好的Channel添加到对应的Poller中,随着越来越多的连接,subLoop的对应的Poller监听的channel会越来越多。
    在这里插入图片描述
    读写和关闭事件与新连接触发方式类似,只是触发的方式和回调所做的工作不同。新连接由mainLoop往eventfd发数据,在subLoop的wakeupChanne上触发;读写和关闭事件是客户端往connfd发数据,在subLoop的普通Channel上触发。

  • 相关阅读:
    dplyr 中的filter报错:Can‘t transform a data frame with duplicate names
    MATLAB算法实战应用案例精讲-【数模应用】朴素贝叶斯(NB)(附Java、R语言、Python和MATLAB代码)
    IronPDF for Java 2023.9.2 Crack
    Redis(十) 布隆过滤器
    Linux网络编程基础
    Hadoop3:MapReduce之简介、WordCount案例源码阅读、简单功能开发
    互联网摸鱼日报(2023-05-28)
    sqlserver6
    配置定时任务的 cron 表达式有哪几种?
    CAS-认证原理及实践
  • 原文地址:https://blog.csdn.net/weixin_43973403/article/details/126218524