所有使用asio的代码必须从定义一个io_service对象开始,那么io_service究竟实现了什么功能呢,
为了解决这个问题,首先我们从asio根目录的io_service.hpp开始入手分析代码,这个文件主要是声明类io_service.
其实根据asio作者给的注释,asio的核心功能已经很清楚了,可以看下面copy的代码:
The io_service class provides the core I/O functionality for users of the
asynchronous I/O objects, including:
@li boost::asio::ip::tcp::socket
@li boost::asio::ip::tcp::acceptor
@li boost::asio::ip::udp::socket
@li boost::asio::deadline_timer.
粪便实现了tcp upd 协议,acceptor,deadline_timer定时器类。
类的构成:
io_service的主要功能是在下面三个类实现的,后面我们将通过acceptor的实现来看一下这个框架的使用
boost::asio::detail::service_registry* service_registry_;
impl_type& impl_;
class service;
1]首先看下service这个类,这个类及其简单主要是为了派生子类的,下面是作者注释:
Base class for all io_service services
acceptor就是从这个类派生出来:
class socket_acceptor_service
: public boost::asio::io_service::service
2]boost::asio::detail::service_registry* service_registry_;
类的声明在detail/impl/service_registry.hpp这个文件中,很简单,其实就是实现了一个单链表,
所有派生自class service;类都自动加入到单链表service_registry_
下面通过acceptor_service来看下service是怎么加入到链表的:
首先每个继承自service的类都有一个代理类,通过代理类来实现具体的功能,在acceptor功能实现中这个代理类是reactive_socket_service_base,在这个类的构造函数中调用
use_service加入到service_registry_链表(这个use_service会首先查找是否再链表中,如果没有
会自动再尾部插入一个节点。)
具体代码:
./detail/impl/reactive_socket_service_base.ipp: : reactor_(use_service(io_service))
3]最重要的一个成员类impl_type,这个实际上就是io_service的代理类,所有的具体iocp功能
都会在这个里面实现,包括我们常用的run post方法,所有的asio服务也是使用这个类完成相应的功能。
下面是impl_type类在io_service.hpp中的声明
#if defined(BOOST_ASIO_HAS_IOCP)
typedef class win_iocp_io_service io_service_impl;
class win_iocp_overlapped_ptr;
#else
typedef class task_io_service io_service_impl;
#endif
从上面定义可以看到,由于window实现了iocp功能,所以会调用win_iocp_overlapped_ptr使用window自带的
iocp功能,否则就使用task_io_service来自己实现一个iocp功能,由于我们主要使用linux,下面我们只是分析
的实现,声明在下面文件detail/task_io_service.hpp中,基本就是io_service post run等函数声明
post的具体实现在detail/impl/task_io_service.hpp中,分析代码我们可以看到主要是讲具体的任务放到
op_queue op_queue_[max_ops];
队列中立即返回了,后面会有run函数完成队列中的任务。
run的具体实现在detail/impl/task_io_service.ipp中,不考虑windows
在linux上面具体的实现在detail/impl/epoll_reactor.ipp中,最终还是调用了epoll来完成:
通过epoll_wait来实现事件驱动的读写,将数据写到一个队列中,然后通过start_op函数来实现数据处理(供socket调用)。
阅读(4017) | 评论(0) | 转发(0) |