Boost asio 原理详解分析:linux 封装 epoll实现/ windows iocp 实现

http://www.cnblogs.com/sanjin/archive/2012/08/10/2631556.html

http://blog.chinaunix.net/uid-23093301-id-2942313.html

这两天事情不多,简单看了下boost.asio的源码,因为asio采用proactor模式,而windows下的IOCP本身就是这个模式的体现,所以将精力集中在了asio在linux下的实现(asio在windows下采用了IOCP,linux下用epoll,还有其它的一些实现如kqueue,select等).

在高性能服务器并发模型设计中,Reactor和Proactor是两个经常用到的设计模式,前者用于同步IO,后者用于异步IO,前者在IO操作就绪的情况下通知用户,用户再采取实际的IO操作,后者是在IO操作完成后通知用户,举个简单的例子,比如说你有一封信到了邮局,Reactor模式就是邮局的人到你家来告诉你说你有信件,然后你到邮局去拿,而Proactor模式则是邮局的把信件送到了你家.在我看来IOCP的设计就是Proactor模式的完美体现,而epoll则很容易实现Reactor模式,asio设计为跨平台,并且在linux下采用epoll,我的印象中linux对异步IO的支持没有windows那么完善(看看IOCP和epoll模型的区别就知道),那么asio是怎么用epoll机制实现proactor模式的呢,刚开始想的是应该在应用层做了一层封装,就是asio内部应该有某个循环调用epoll_wait,当有IO事件就绪时帮用户做一些操作(比如把数据拷贝到我们提交的缓冲区),然后在操作完成的时候调用我们的handler(后来看代码基本是这样).OK,不说废话了.

 

 

Boost ASIO proactor 浅析 2011-10-07 18:36:35

分类: C/C++

Boost ASIO proactor  浅析前情提要:

Boost asio socket的异步非阻塞模式才有的是proactor模式,当IO操作介绍后回调相应的处理函数。ASIOLinux平台下的实现基于epoll,但是epoll只支持reactor模式,ASIO通过封装在epoll上实现了proactor。提到ASIO proactorASIO中的所有异步操作都是基于io_service实现的,io_serviceASIO中的任务队列,并且他负责调用epoll_wait等待IO事件到来,对io_service的实现参加前边的bloghttp://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中了。显然epollReactor的。

ASIO  的实现:Epoll 的封装:

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

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

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

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

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

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

l start_op的实现:

n Start_op需要事件的类型、文件描述符、回调函数做参数,首先调用perform,也就是直接sendsend若成功直接调用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 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,而 stream_socket_service声明文件为boost/asio/stream_socket_service.hppL60

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

boost/asio/detail/reactive_socket_service.hpp

l async_send操作实现逻辑为:

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

 

你可能感兴趣的:(Boost asio 原理详解分析:linux 封装 epoll实现/ windows iocp 实现)