> For the complete documentation index, see [llms.txt](https://xd96dx.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://xd96dx.gitbook.io/docs/c-c++/wang-luo-bian-cheng/reactor-shi-li-zhi-muduo-yuan-ma-fen-xi.md).

# Reactor实例之 muduo 源码分析

Reactor 模型的实践库, 源码不难, 也很好分析, 和 beegfs 网络部分代码很像, 不过都大同小异

### Reactor主要组件

#### EventLoop:&#x20;

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FsysE6DFNXv3E5WgwmO2L%2Fimage.png?alt=media&amp;token=8bc0e446-0ded-48d1-95bf-3a3ed2e31fe6" alt=""><figcaption></figcaption></figure>

eventLoop 封装了Poller 和 Channel, 是muduo的事件循环, 负责事件处理, 任务分发, 定时器等功能

* **looping**   表示事件循环是否正在运行, 在loop 时会设置为true, 退出后设为false
* **quit\_** : 事件循环是否退出
* **eventHandling**: 表示是否正在处理事件
* **callingPendingFunctors**: 表示是否正在执行线程安全的任务队列
* **iteration**: 事件循环次数
* **threadId\_**: eventLoop 的线程id
* **pollReturnTime\_**: poller 返回的时间戳
* **poller**: 在linux下, 就是epoll, 用来监听channel 注册的事件
* **timerQueue**: 定时管理器, 触发定时任务
* **weakupChannel\_** 是用来监听 **weakupFd\_** 的, 他们和 **pendingFunctors** 是关联的, 在跨线程提交任务后,   weakupChannel\_ 会被 weakUp() 唤醒, 将任务放入 pendingFunctors 里, 在loop 中执行, 并清除weakupFd\_ 的可读状态, 作用就是可以周期性的执行一部分其他线程提交的任务, 并恢复原状态
* **activeChannels**: Poller里活跃的事件列表
* **currentActiveChannel\_**: 当前正在处理的channel
* **mutex\_**: 用来保护 pendingFunctors\_ (主要是push\_back, swap)

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2Fs9YjbZWlUjoUR318OUzK%2Fimage.png?alt=media&amp;token=fe12be5e-c7f3-47aa-8d88-253edfa51f4f" alt=""><figcaption><p>loop</p></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FnyhstDrkVVnLB7ZjRr4u%2Fimage.png?alt=media&amp;token=65f925cb-9d8c-460b-a84e-2b702ecc141a" alt=""><figcaption></figcaption></figure>

这是eventLoop 的 loop 方法, 监听poller 的事件, 然后执行, dopendingFunctors 里执行其他线程提交的任务, 不断循环&#x20;

#### Channel

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2Fun3c9sjufwPkvKgBQWat%2Fimage.png?alt=media&amp;token=e43bc120-697b-4993-9911-0e438bb90ca8" alt=""><figcaption><p>channel</p></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FyywQAsfblEURp7BnVjfF%2Fimage.png?alt=media&amp;token=c1b3d188-68a7-4fbc-bbb9-9ed5e8e52b6d" alt=""><figcaption><p>事件封装</p></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FrjrzdDUbJDULP4I4EaUj%2Fimage.png?alt=media&amp;token=47274af0-c298-48b9-85e1-3b8226dc595a" alt=""><figcaption><p>回调函数</p></figcaption></figure>

channel 主要用于封装fd 和 事件处理的回调, 负责具体事件的监听和处理

* &#x20;**loop\_** : 关联一个eventLoop 对象, 并将其注册到poller(epoll), 监听文件描述符事件
* &#x20;**fd\_** : io 描述符
* &#x20;**events\_**: channel 要监听的事件, 事件发生时, poller 通知eventLoop, 并执行回调
* &#x20;**revents\_** : 实际发生的事件, 用来和监听的事件对比, 是否要执行相应注册的回调函数
* &#x20;**index\_** : poller中的索引
* &#x20;**logHup\_** : 是否记录挂起事件
* &#x20;**tie\_** : channel 与其他对象共享生命周期时, 用来绑定channel, muduo里使用的有 tcpConnection 和 curl
* &#x20;**tied\_ :** 是否已经绑定对象
* **eventHandling:** eventLoop 是否正在处理channel 的事件
* &#x20;**addedToLoop\_ :** channel 是否已经添加到eventLoop中
* &#x20;**readCallback\_, writeCallback\_, closeCallback\_, errorCallback\_** : 对应事件注册的回调函数

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FbExW0vhw9KqSSzMTBTQS%2Fimage.png?alt=media&amp;token=30586f36-a11d-4573-bc69-973f779bdce6" alt=""><figcaption><p>事件处理</p></figcaption></figure>

#### Poller

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FRoUoh3p2CsQje6QGsMc3%2Fimage.png?alt=media&amp;token=a640ede4-7d70-4282-b199-6d4903a459d2" alt=""><figcaption><p>poller</p></figcaption></figure>

* **channels:** 存储所有注册到poller的channel
* **ownerLoop\_:** 指向channel或poller的eventLoop

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FWR6mUYGAm3T1QRtVB2ob%2Fimage.png?alt=media&amp;token=13c13195-7aaf-4d9f-9aaf-75d428e05424" alt=""><figcaption></figcaption></figure>

&#x20;Poller 作为基类, 封装io多路复用, 在linux 下为epoll

* **epollfd\_**: epoll 文件描述符
* **events**: 存储epoll\_wait() 返回的事件

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FAOrmF8J4Sr6fRFFijan6%2Fimage.png?alt=media&amp;token=4177326d-20cb-4725-b4b0-4c480dc097fa" alt=""><figcaption><p>epoller</p></figcaption></figure>

epoll主要流程

### 主要流程&#x20;

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FXl2L8WG0HM70NPP3k1sC%2Fimage.png?alt=media&amp;token=1685c4d0-4163-4688-b605-e19508cd56e1" alt=""><figcaption></figcaption></figure>

EventLoop 作为muduo的事件循环, 在TcpServer.h 中, 主要给Acceptor 来建立新连接, 是整个tcpServer的起点, **Acceptor** 来监听事件, 并分发给其他工作线程

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2F1HB18JTZQ27rMTAya2s1%2Fimage.png?alt=media&amp;token=3644b0cb-996f-47f6-be0c-abbf4b870127" alt=""><figcaption><p>accptor init</p></figcaption></figure>

acceptor 在初始化时, 绑定 sever 的eventLoop, 并设置新连接进入的回调

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2Fj1nne1LUauKcz7maJIit%2Fimage.png?alt=media&amp;token=dc36400a-84c4-44c3-a861-74b7b75ba6b7" alt=""><figcaption><p>threaPool start</p></figcaption></figure>

start时, acceptor 开启监听并接受新连接, 线程池开始运作

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FYVhuTJvWXdtWZgH0o6SI%2Fimage.png?alt=media&amp;token=e04811d3-01f9-4716-8523-c56d188affcd" alt=""><figcaption><p>newConnection</p></figcaption></figure>

在新连接进入时, 从线程池拿一个eventLoop, 并绑定 TcpConnection, 监听其事件

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2F2j788Y5Hp44s2psfp71d%2Fimage.png?alt=media&amp;token=c5ade211-ca23-4e01-a290-38ef1d619b5c" alt=""><figcaption><p>tcpConnection</p></figcaption></figure>

建立新的tcpConnection, 并绑定读写关闭错误事件

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FxZg6CnUFaEvAhkbVJdgE%2Fimage.png?alt=media&amp;token=cb420876-07f1-46bd-afca-b913c1b44144" alt=""><figcaption><p>read事件</p></figcaption></figure>

如read事件, 从channel 拿出fd, 并读取fd的内容, 即完成一次都事件, 其他事件类似相同
