从第一个boost.asio的教程开始,boost文档就一直在告诉我们:使用boost.asio第一步就是要创建一个io_service对象。那么io_service是个什么东西呢?
boost.asio文档说,io_service为下面的这些异步IO对象提供最核心的IO功能:
接着,文档就会说,像下面这样,就可以简简单单声明一个io_service对象了:
int main() { boost::asio::io_service io; |
上面的一行代码,表明无限地风光与潇洒,看起来简简单单一行,就几乎有了异步IO、网络操作的框架,那么他到底代表了什么,在后面,又有什么事情发生呢?io_service又是如何支撑起这些功能的呢?带着这些问题,我们开始分析吧……
从C++的角度看,上面的这一行代码,无非就是定义了一个io_service的实例,而C++的底层机制所隐藏起来的东西,无非就是初始化该对象的所有数据成员。再来看io_service的声明,我们知道,该类除了一堆成员函数之外,事实上只有三个成员(暗想:这几个成员肯定很是神奇无匹了):
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) detail::winsock_init<>init_; #elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ || defined(__osf__) detail::signal_init<> init_; #endif
// The service registry. boost::asio::detail::service_registry*service_registry_;
// The implementation. impl_type&impl_; |
暂时抛开那几个成员,再来看一下io_service比较重要的一个函数:run()的实现,发现该函数也就是将真正的功能委托给成员impl_去做事儿了:
std::size_t io_service::run() { boost::system::error_code ec; std::size_t s = impl_.run(ec); boost::asio::detail::throw_error(ec); return s; } |
种种迹象表明,impl_是个巨牛的东西了。统揽io_service的实现,我们不难发现,该类的所有功能,几乎都是委托给了impl_成员去干了——典型的“有事秘书干”。不过想想也挺容易理解的,io_service提供了一个上层的接口,充当抛头露面的BOSS,真正的工作则委托给下一层的员工去实现——哪家公司不是这样呢?
所以,要想了解io_service的玄机,就需要弄清楚这三个数据成员到底是什么来历,特别是impl_的来历才行。
成员init_在io_service的各个函数中,并没有显式用到。其存在的价值,就在于该类的构造函数里面,调用了初始化相关的代码,具体到Windows平台,就是WinSock的初始化,也就是调用 ::WSAStartup() 这一WinSock编程所必须调用的第一个函数;而其析构函数则进行清理工作,同样交由WinSock函数 :: WSACleanup()完成。
也就是说,io_service通过init_数据成员的创建与销毁,自动完成了相关的初始化及清理工作。
前面说过,impl_带着无限的神秘默默地完成了io_service::run()的功能。至于他到底是什么style,现在来揭开盖头吧。
从直接声明来看,impl_具有 impl_type&类型。用SourceInsight不难发现该类型只不过是一个类型别名:
typedef detail::io_service_impl impl_type;
一波未平一波又起,这儿又冒出个io_service_impl。继续刨根问底,找到:
#if defined(BOOST_ASIO_HAS_IOCP)
namespace detail { typedefwin_iocp_io_service io_service_impl; }
#else
namespace detail { typedeftask_io_service io_service_impl; }
#endif
终于知道,在某些情况下,它是win_iocp_ ,在某些情况下,是task_。事实上,在Win NT环境下,如果没有禁用IOCP,也就是没有声明BOOST_ASIO_DISABLE_IOCP这个预处理器指令,那么asio就采用win_iocp_io_service来做那些脏活累活;在剩下的其他平台,或者Win上禁用了IOCP,则使用task_io_service来做事儿了。
先稍微提一下,win_iocp_io_service是对Windows环境下的IOCP(完成端口IO)模型的封装,该类作为boost.asio在Windows下的核心,我们在后面详细分析其实现。
io_service的另外一个数据成员service_registry_,又具备什么样的身份和功能呢?我们来看看io_service的构造函数:
io_service::io_service() : service_registry_ ( new boost::asio::detail::service_registry( *this, static_cast (std::numeric_limits ) ), impl_(service_registry_->first_service { } |
构造函数为了初始化service_registry_,动态分配了一个boost::asio::detail:: service_registry类对象。为了构造该对象,提供了三个参数:
再来观察service_registry的实现,发现其实际就是一个链表,管理io_service所容纳的所有service对象(win_iocp_io_service就是一种service)。每种service都有一个id,链表以此id作为标志,在客户通过io_service来请求一种服务时,例如调用 use_service
asio提供了这样几个函数,来进行service的管理和使用——这也为扩展asio提供了可能,例如可以自己定义一种服务,使用add_service加入io_service进行管理。
Service& use_service(io_service& ios);
void add_service(io_service& ios, Service* svc);
bool has_service(io_service& ios);
|
|
|
|
|
boost::asio::io_service |
|
|
|
|
class boost::asio::io_service::::id |
|
|
|
|
|
|
class boost::asio::io_service::work |
|
|
|
|
|
|
|
enum boost::asio::io_service::fork_event |
|
|
|
|
|
|
|
class boost::asio::io_service::strand |
|
|
|
|
|
|
|
class boost::asio::io_service::service |
|
|
|
|
|
|
io_service内部定义了这样一些类型,来为其服务:
针对service类型,asio从其派生出了数十个类分别完成不同的功能,例如在Win上充当io_service的win_iocp_io_service类,以及为各种IO Object类型提供服务的类,如对应于TCP的stream_socket_service,对应于UDP的datagram_socket_ service。下图显示了asio常用到的服务类,及其针对不同平台的适配类之间的关系。
图中左边的类,会在我们的应用程序中直接用到(由于asio又对这些类提供了一层动态组装,所以代码中不会去直接声明这些类型的实例,但是剥掉动态组装的外衣,我们声明的仍然是这些类的实例,具体在下面一部分说明),作为应用层的类;而右边部分,则是针对不同平台所提供的不同实现,作为平台适配层。
应用层类在编译时,根据所在平台(其实是喂给编译器的各种预处理宏,如BOOST_ASIO_ HAS_IOCP),选择对应的类进行编译。例如用于TCP的服务类stream_socket_service是这样进行选择的:
template
class stream_socket_service
{
private:
// The type of the platform-specific implementation.
#if defined(BOOST_ASIO_HAS_IOCP)
typedef detail::win_iocp_socket_service
#else
typedef detail::reactive_socket_service
#endif
// The platform-specific implementation.
service_impl_type service_impl_;
…
};
其他需要进行平台决策的类型,都是采用这种技术,来选择不同的实现的。
从io_service::service派生的完整的类列表如下:
还有几个非常重要的类,他们作为劳苦大众在金字塔底层默默提供service功能,但却没有从io_service::service派生;他们是上述那些服务类在各个平台的具体实现,为金字塔中间层的服务类提供再服务的(不难想象,提供服务的方式,又是那种“有事儿秘书干”的方式):