从epoll构建muduo-11 单线程Reactor网络模型成型
mini-muduo版本传送门
version 0.00 从epoll构建muduo-1 mini-muduo介绍
version 0.01 从epoll构建muduo-2 最简单的epoll
version 0.02 从epoll构建muduo-3 加入第一个类,顺便介绍reactor
version 0.03 从epoll构建muduo-4 加入Channel
version 0.04 从epoll构建muduo-5 加入Acceptor和TcpConnection
version 0.05 从epoll构建muduo-6 加入EventLoop和Epoll
version 0.06 从epoll构建muduo-7 加入IMuduoUser
version 0.07 从epoll构建muduo-8 加入发送缓冲区和接收缓冲区
version 0.08 从epoll构建muduo-9 加入onWriteComplate回调和Buffer
version 0.09 从epoll构建muduo-10 Timer定时器
version 0.10 从epoll构建muduo-11 单线程Reactor网络模型成型
mini-muduo v0.10版本,修整代码版本。mini-muduo完整可运行的示例可从github下载,使用命令git checkout v0.10可切换到此版本,在线浏览此版本到这里。
这个版本的改动不大,主要修改了命名规范问题,借着这个版本重点分析一下muduo里的三个文件描述符。
命名规范
1 Channel::getSocketfd() 改为Channel::getfd()
Channel一开始只是用来包装socket描述符的,但是后面eventfd和timerfd都加入进来,所以改名为getfd()才合适。
2 修改了几个Channel成员变量的命名,直接用Channel所包装的文件描述符命名,更直观,比如下面这几个。
_wakeupChannel => _pEventfdChannel
_pChannel=>_pSocketChannel
_pAcceptChannel=>_pSocketAChannel
三种文件描述符
Muduo里有三个重要的文件描述符,1 socket fd 2 event fd 3 timer fd,这三个文件描述符外加一个epoll循环构成了整个程序运行的框架。可以看出,muduo库作者有意把各种需求都整合到epoll里,后续甚至连任务在多个线程间的分发都交给了epoll描述符。我们只要明白了muduo的这种独特设计思路,就几乎理解了其完整工作流程。
图示表明了这三个文件描述符在epoll_wait中的执行流程。主流程里有一个while循环(位于EventLoop.cc中),不断调用epoll_wait来尝试获得新的通知,三种描述符都已经被加入epoll_wait监听,所以三个描述符上只要有read类事件发生,epoll_wait会返回,对应的Channel::handleRead()会被调用。三种描述符有各自的处理流程,handleRead处理完毕后,while循环还未完结,需要继续调用doPendingFunctors(位于EventLoop.cc中)来执行异步待处理的回调,之后完成本次循环。
1 socket fd
作为网络IO的核心,socket描述符的作用不必多说,所有的网络数据输入输出都通过它来完成。(之前的介绍可参看
链接 <<从epoll构建muduo-5 加入Acceptor和TcpConnection>>)。有两种socket描述符,一种用来listen新的连接,另一种用来读写数据,这里我们只关心后者。对读写数据的socket(位于TcpConnection.cc中)来说,其handleRead,或者更直接点是用户回调里的onMessage(),也就是服务器收到一个协议后的处理逻辑。可能会有下面这些操作,比如”读写数据库“或者"触发一个异步调用"或者"开启定时器做事情"等等,由于后两个操作会与eventfd/timerfd产生关联,所以这里只画出了这两个操作。这两个操作分别对应于EventLoop::queueLoop方法和TimerQueue::addTimer方法。
2 event fd
提供了一个异步调用接口,这个异步调用可能来自本线程(比如本线程的Timer),或者来自其他线程(多线程的章节涉及,先忽略),之前的介绍参看 连接 <<从epoll构建muduo-9 加入onWriteComplate回调和Buffer>>
异步调用过程如下
1 通过调用EventLoop::queryLoop送入一个IRun*和一个void*参数,后续当异步调用发生时,参数会被重新送给IRun。
2 EventLoop::queryLoop的实现做了两件事
1把一个IRun放到pending vector(即图中vectorA)
2向eventfd写入一个uint_64(多线程版本才有意义,先忽略)。
3 socket的handleRead()之后调用doPendingFunctors,这里会遍历pending vector,并触发我们刚放入的IRun(void*),本次epoll循环结束。
4 下次循环到达epoll_wait 由于向event fd写入了字节而导致epoll_wait返回,包含有event fd的Channel::handleRead被调用,在handleRead中, 必须读取一个字节出来,否则会导致epoll_wait在下次循环中再次触发event fd,而这不是我们想要的结果,我们只希望event fd的handleRead被调用一次(多线程版本才有意义,先忽略)。
3 timerfd
实现了定时器功能。(之前的介绍参看 连接 <<从epoll构建muduo-10 Timer定时器>>)
1 添加定时器的入口TimerQueue::addTimer,这是一个异步操作,是通过EventLoop::queryLoop实现的。
2 按照刚才讲的event fd处理流程,异步操作会在之后的doPendingFunctors触发,被触发的将是TimerQueue::doAddTimer函数。
3 TimerQueue::doAddTimer做下面两件事
1将Timer插入定时器集合中(vectorB)
2找出这个定时器是否比已知定时器里最早要发生的定时器还早,如果是,则调用resetTimerfd()将timer fd往更早修改。
4 当Timerfd对应的定时器时间到后,epoll_wait会返回,这导致timer fd的handleRead()被调用。handleRead做了下面的事情
1 遍历定时器列表,将当前事件之前应该触发的调用全部调用一次IRun
2 找到已经触发过,但是需要重复执行的定时器,将其后延一个时间单位,插入到定时器回调集合中(VectorB)
3 从定时器回调集合(vectorB)里找出最近的一个未执行的条目,然后设置timer fd到这个时间。
5 定时器完整过程处理完毕。
从epoll构建muduo-11 单线程Reactor网络模型成型的更多相关文章
- 从epoll构建muduo-13 Reactor + ThreadPool 成型
mini-muduo版本号传送门 version 0.00 从epoll构建muduo-1 mini-muduo介绍 version 0.01 从epoll构建muduo-2 最简单的epoll ve ...
- 从epoll构建muduo-12 多线程入场
mini-muduo版本号传送门 version 0.00 从epoll构建muduo-1 mini-muduo介绍 version 0.01 从epoll构建muduo-2 最简单的epoll ve ...
- muduo简化(1):Reactor的关键结构
说明:本文参照muduo代码,主要用意是简化muduo代码呈现其主要结构,并脱离muduo的文件依赖. 本节简化的是Reactor的关键结构部分:EventLoop.Poller.Channel.遵照 ...
- muduo源代码分析--Reactor模式在muduo中的使用
一. Reactor模式简单介绍 Reactor释义"反应堆",是一种事件驱动机制.和普通函数调用的不同之处在于:应用程序不是主动的调用某个API完毕处理.而是恰恰相反.React ...
- muduo源代码分析--Reactor在模型muduo使用(两)
一. TcpServer分类: 管理所有的TCP客户连接,TcpServer对于用户直接使用,直接控制由用户生活. 用户只需要设置相应的回调函数(消息处理messageCallback)然后TcpSe ...
- 从epoll构建muduo-1 mini-muduo介绍
https://blog.csdn.net/voidccc/article/details/8719752 ========== https://blog.csdn.net/liangzhao_jay ...
- Reactor模式解析——muduo网络库
最近一段时间阅读了muduo源码,读完的感受有一个感受就是有点乱.当然不是说代码乱,是我可能还没有完全消化和理解.为了更好的学习这个库,还是要来写一些东西促进一下. 我一边读一边尝试在一些地方改用c+ ...
- Go netpoll I/O 多路复用构建原生网络模型之源码深度解析
导言 Go 基于 I/O multiplexing 和 goroutine 构建了一个简洁而高性能的原生网络模型(基于 Go 的I/O 多路复用 netpoll),提供了 goroutine-per- ...
- reactor模式:单线程的reactor模式
reactor模式称之为响应器模式,常用于nio的网络通信框架,其服务架构图如下 不同于传统IO的串行调度方式,NIO把整个服务请求分为五个阶段 read:接收到请求,读取数据 decode:解码数据 ...
随机推荐
- 安装Microsoft oneDrive(原skyDrive)
oneDrive下载地址:https://onedrive.live.com/about/zh-cn/download/ 安装时报错:Error 0x80040ca0 解决方案:关闭安装程序,按下面的 ...
- ajax分页实现,jquery.pagination.js
1.前台使用ajax无刷新分页,主要需要生成分页的工具条,这里使用的是jquery.pagination.js 插件参数可以参考----张龙豪-jquery.pagination.js分页 下面贴出代 ...
- android 广播分类
安卓广播分为两类:1.普通广播, broadcast,广播发出之后所有满足条件的应用都能获取到广播里面的数据,缺点是应用获取广播中的数据修改之后不能传递给其它接收广播的应用:2.有序广播,orderb ...
- [php基础]PHP Form表单验证:PHP form validator使用说明
在PHP网站开发建设中,用户注册.留言是必不可少的功能,用户提交的信息数据都是通过Form表单提交,为了保证数据的完整性.安全性,PHP Form表单验证是过滤数据的首要环节,PHP对表单提交数据的验 ...
- 关于android:screenOrientation="portrait"等
1.android:screenOrientation="portrait",表示当切换横竖屏的时候,屏幕的内容始终以竖屏显示,而不会根据屏幕的方向来显示内容. 2.插入个Andr ...
- 日期 bootsrtap-datatimepicker and bootstrap-datepicker 控件支持中文
引用 bootsrtap-datatimepicker and bootstrap-datepicker 控件,发现官方控件不支持中文 1,bootstrap-datepicker - >解决方 ...
- ASP.NET页面传值与跳转
asp.net页面传值的五种方法:QueryString,Session,Application,Request.Cookies,Server.Transfer 其中Cookie和Server.Tra ...
- 基础知识 mfc
句柄 资源的标示 图标句柄(HICON) 光标句柄(HCURSOR) 窗口句柄(HWND) 类似于指针 wm_keydown表示键盘上的按键按下了数值 WPARAM ||LPARAM 两个整形数据 ...
- li的border无法和上边对齐
如果利用border设置四周的border,如果一边的边框比较长无法对齐 解决办法: .test{ position: relative; border: 1px solid #808080; hei ...
- flask开发restful api系列(6)-配置文件
任何一个好的程序,配置文件必不可少,而且非常重要.配置文件里存储了连接数据库,redis的用户密码,不允许有任何闪失.要有灵活性,用户可以自己配置:生产环境和开发环境要分开,最好能简单的修改一个东西, ...