Boost ASIO proactor 浅析

Boost ASIO proactor 浅析

前情提要:

Boost asio 的socket的异步非阻塞模式才有的是proactor模式,当IO操作介绍后回调相应的处理函数。ASIO在Linux平台下的实现基于epoll,但是epoll只支持reactor模式,ASIO通过封装在epoll上实现了proactor。提到ASIO proactor,ASIO中的所有异步操作都是基于io_service实现的,io_service是ASIO中的任务队列,并且他负责调用epoll_wait等待IO事件到来,对io_service的实现参加前边的blog:http://www.cnblogs.com/zhiranok/archive/2011/09/04/boost_asio_io_service_CPP.html

Proactor 和 Rector:

两种设计模式网上已经有很多种解释,这两种模式都是针对IO操作的,我的理解是Rector只是告诉调用者什么时候事件到来,但是需要进行什么操作,需要调用者自己处理。Preactor不是当事件到来时通知,而是针对此事件对应的操作完成时,通知调用者,一般通知方式都是异步回调。举例,Reactor中注册读事件,那么文件描述符可读时,需要调用者自己调用read系统调用读取数据,若工作在Preactor模式,注册读事件,同时提供一个buffer用于存储读取的数据,那么Preactor通过回调函数通知用户时,用户无需在调用系统调用读取数据,因为数据已经存储在buffer中了。显然epoll是Reactor的。

ASIO 的实现:

Epoll的封装:

l boost/asio/detail/epoll_reactor.hpp 是epoll_reatcor的封装,class epoll_reactor有两个作用,任务队列和调用epoll_wait,支持的操作类型有read、write、connect、except。其实现文件为boost/asio/etail/impl/epoll_reactor.ipp,主要的实现逻辑有run和start_op。

n Run函数的逻辑是:调用一次epoll_wait,得到相应的IO事件

n 遍历相应IO事件,若是专门用于中断epoll操作的文件描述符那么跳过

n 若是用于定时器的文件描述符,则设置标志变量check_timers为true

n 若是基本IO事件,依次检查其IN、OUT事件,except事件会首先检测,将次事件对应的队列上的操作全部执行完毕(先调用io_servie::post,然后被调用)。

n 若check_timers标志变量被设置,那么将已经超时的操作通过io_service::post调用

l start_op的实现:

n Start_op需要事件的类型、文件描述符、回调函数做参数,首先调用perform,也就是直接send,send若成功直接调用io_service::post调用回调函数

n 如果文件描述符没有注册到epoll_wait,那么EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET 全部注册到epoll_wait。

n 每个文件描述符有自己的队列,该事件的回调函数会被添加到队列中。

boost::asio::ip::tcp::socket中的异步方法的实现

l Socket中有async_打头的许多异步方法,这里已async_send为例

l boost/asio/ip/tcp.hpp 声明了tcp::socket的原型,实际原型是

typedef basic_stream_socket<tcp> socket;

l basic_stream_socket是模板类,声明在boost/asio/basic_stream_socket.hpp文件中,async_send操作只是简单的为

this->service.async_send(this->implementation, buffers, 0, handler);

而service的原型是什么呢?

basic_stream_socket继承于basic_socket<Protocol, stream_socket_service>,而 stream_socket_service声明文件为boost/asio/stream_socket_service.hpp,L60中

typedef detail::reactive_socket_service<Protocol> service_impl_type;告诉我们service的原 型是detail::reactive_socket_service<tcp>,其声明文件为

boost/asio/detail/reactive_socket_service.hpp

l async_send操作实现逻辑为:

n 先分配一个回调函数,调用start_op,start_op的实现在detail/reactive_socket_service_base.ipp文件中,只是简单的向epoll_reactor调用start_op方法注册write_op。start_op在上面的段落中已经讲到了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大数据钻研

前端编码规范

基本原则 结构、样式、行为分离 统一缩进(建议 两个空格) 文件编码统一 不带BOM的UTF-8 一律使用小写字母 省略外链资源 URL 协议部分(FTP等其他...

2857
来自专栏PHP技术

jQuery学习笔记

jQuery大部分功能需要根据文档的DOM模型来工作,首先需要正确地解析到整个文档的DOM模型结构。使用jQuery需要在整个文档被浏览器完全加载后才开始进行。

772
来自专栏Python中文社区

一文读懂Python装饰器由来(一)

Python装饰器是非常不错的特性,熟练掌握装饰器会让你的编程思路更加宽广,程序也更加pythonic。下面就让我们一起来探讨一下python的装饰器吧。

872
来自专栏Java技术

MyBatis关联映射:一对一、一对多总结一二

(3)用户实体对象,com.xuliugen.mybatis.demo.bean.User

691
来自专栏C/C++基础

web前端开发初学者十问集锦(4)

利用JS来控制页面控件的显示和隐藏有两种方法,两种方法分别利用HTML的style中的两个属性,两种方法的不同之处在于控件隐藏后是否还在页面上占空位。

1272
来自专栏静晴轩

精妙JS代码段搜集

现在到处都是JavaScript,倘若花点时间去体察,每次都能知道点新的东西。一旦你入了门,你总能从这里或是那里领悟到很多知识。一旦发现些许有意思的东西,总习惯...

3195
来自专栏dotnet core相关

datatables 配套bootstrap样式使用小结(2) ajax篇

上一篇是介绍一下基本的用法,基本的原理是取出所有的数据,然后调用$.datatables(option)方法格式化,这种方法显然不太科学,所以ajax方式是必须...

621
来自专栏LanceToBigData

XML(一)XML大揭秘

前言 每天都要学习很多新的知识,比你厉害的程序员比你还努力,那你混的下这口饭吗?所以不抱怨,坚持!接下来给大家分享的是xml。可能很多做开发的都遇到过xml, ...

1829
来自专栏九彩拼盘的叨叨叨

使用 CSS 伪元素需要注意的

若不设置,则伪元素不会显示。如果不想设置 content 的内容,可以将内容设置为空。如:

522
来自专栏我有一个梦想

QT Creator 快速入门教程 读书笔记(三)

一   信号和槽   GUI 程序除了要绘制控件,还要响应系统和用户事件,例如重绘、绘制完成、点击鼠标、敲击键盘等。当事件发生时,UI 会产生相应的变化,让用户...

2198

扫码关注云+社区