您的位置:首页 > 移动开发 > Objective-C

boost.asio学习笔记03——io objects

2013-09-23 16:10 295 查看
asio的文档,告诉我们在声明一个io_service对象之后,就可以创建io对象去干活了,例如:

int main(int argc, char* argv[])

{

boost::asio::io_service io_service;

tcp::resolver resolver(io_service);

tcp::resolver::query query("www.boost.org",
"80");

tcp::resolver::iterator iterator = resolver.resolve(query);

上图中main()的第二行代码声明了一个tcp::resolver对象,后续进行地址解析的逻辑,都是围绕此resolver对象展开的。那么这个resolver是一个什么样的类型呢?阅读源代码我们在boost::asio::ip::tcp类内部看到了这样的类型别名定义:

typedef basic_resolver<tcp> resolver;

是否似曾相识呢?是的,这和我们STL中的string, iostream等一样,使用的都是某个模板类的一个实例。这里的resolver是basic_resolver在tcp模版参数下的实例,string是basic_string在char模版参数下的实例——boost库和STL库统一风格的一个体现。

asio大量采用这种技术,所有和resolver一样提供io功能的类,都是某个baisc_
模版类的实例化。下面我们来研究一下asio的io object逻辑。

io object 类关系网

继续向上追溯basic_resolver,知道该类从basic_io_object派生,主要负责地址解析相关的操作,提供的主要接口有resolver(), async_resolve()等。

查看整个asio的源代码,我们发现从basic_io_object派生的类不少,他们分别负责一些具体的事务,例如basic_socket_acceptor可以作为一个服务器进行侦听,提供了诸如bind(),
listen()等接口;再如basic_socket类是对socket IO
操作的封装,提供了receive(), async_receive(), read_some(), async_readsome(), write_some(), async_write_some()等接口。

整个asio中的io object关系网,我们用下图来显示:



这些io object的功能,简述如下:

basic_deadline_timer提供定时器功能,可以同步等待,也可以异步等待。

basic_waitable_timer
和basic_deadline_timer具有同样的功能,主要区别为该定时器可以和C++ 11中引入的chrono库协作。

basic_signal_set
支持信号相关的操作,异步方式等待单个或者多个信号的发生。
basic_socket_acceptor
作为服务器进行侦听,接收连接请求。
basic_serial_port
对串口操作进行支持。
basic_resolver 地址解析类。

basic_stream_socket
提供同步、异步方式的基于流的socket操作。
basic_datagram_socket
提供同步、异步方式的基于数据报文的socket操作。
basic_raw_socket提供同步、异步方式的基于raw数据的socket操作

basic_seq_packet_socket提供同步、异步方式的基于有序包的socket操作

basic_socket_streambuf ?

basic_object_handle
对windows handle的封装,可以以异步或者同步方式等待
basic_random_access_handle对windows
可随机访问的handle的封装,可以以异步或者同步方式等待

basic_stream_handle对windows面向流handle的封装,可以以异步或者同步方式等待

basic_descriptor
对POSIX描述符进行封装。

另外一点,所有这些io object的构造函数,都要求有一个io_service&
作为参数,使用这一参数,这些io_object对象知道了自己的归属,之后自己所要派发出去的同步、异步操作请求,都将通过自己所在的这个io_service对象来完成。这也就说明了,为什么创建io_service对象是整个asio程序的第一步。

io object服务委托

上述的这些io object类,提供了应用开发中常用的各种“实际”功能,例如地址解析,以及socket读写等,那么这些io object类和第一部分中的service类之间存在着什么样的关系呢?会不会是这些io
object只是一个应用的接口,而具体的功能则委托给service类来完成呢?如果是这样的,那么又是如何实现的呢?

带着这些问题,我们继续研究resolver类的源代码,看看他所提供的功能,到底是如何实现的。

resolver是如何委托的

我们知道,resolver类是在boost::asio::ip::tcp类中的一个类型别名:

typedef basic_resolver<tcp> resolver;

那么,resolver类所提供的async_resolve()接口,就来自于basic_resolver类。再来看看basic_resolver::async_resolve()的实现——该函数有两个重载,我们以其中一个为例:

template <typename
ResolveHandler>

void async_resolve(const
query&
q, BOOST_ASIO_MOVE_ARG(ResolveHandler)
handler)

{

// If you get an error on the following line it means that your handler does

// not meet the documented type requirements for a ResolveHandler.

BOOST_ASIO_RESOLVE_HANDLER_CHECK(

ResolveHandler, handler, iterator)
type_check;

return
this->service.async_resolve(this->implementation,
q,

BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler));

}

可见,async_resolve()果然是委托给了某个service类来做事的——再一次,典型的有事儿秘书干。那么,这儿的“this->service”又是什么呢?

通过跟踪代码的执行,知道该service其实是第一部分曾经提到过的boost::asio::ip::resolver_service,而它又委托给了boost::asio::detail::resolver_service——这家伙再无其他可以委托的对象了,只有苦逼的自己做事儿了——其基本思路就是先创建一个用以地址解析的resolve_op,用这个op来代表本次异步操作,之后启动op去做事情。至于op又是什么东西,稍后在operation部分做介绍;先贴出这段苦主:

// boost::asio::detail::resolver_service

template <typename
Handler>

void async_resolve(implementation_type&
impl,

const
query_type&
query, Handler
handler)

{

// Allocate and construct an operation to wrap the handler.

typedef
resolve_op<Protocol,
Handler>
op;

typename
op::ptr p = { boost::addressof(handler),

boost_asio_handler_alloc_helpers::allocate(

sizeof(op),
handler), 0 };

p.p =
new (p.v) op(impl,
query, io_service_impl_,
handler);

BOOST_ASIO_HANDLER_CREATION((p.p,
"resolver", &impl,
"async_resolve"));

start_resolve_op(p.p);

p.v = p.p = 0;

}

PS:

-
做过Symbian开发的对这种形式似曾相识,这多少和Active Object异曲同工

-
那几行创建op的代码还不是很明白

OK,至此,整个async_resolve()从上到下就拉通了。概括起来,就是io object将具体功能委托给服务类,服务类又委托给和平台实现相关的服务类来完成最后的功能。

io_object的服务创建

通过resolver的执行,我们知道了其层层委托关系,那么resolver所委托的this->service又是怎么来的呢?下面部分,我们来分析io_object所做的服务管理工作。

首先来看该service的具体类型。

要想知道service是如何创建的,我们就要追根朔源找到resolver的具体类型声明,看看到底是如何将service拉上贼船的。好吧,我们再次从头开始(别嫌啰嗦):

typedef basic_resolver<tcp> resolver;

针对这个模版实例,将basic_resolver展开:

template <typename InternetProtocol,

typename ResolverService = resolver_service<InternetProtocol> >

class basic_resolver: public basic_io_object<ResolverService>

à

template <tcp,

typename ResolverService = resolver_service<tcp> >

class basic_resolver: public basic_io_object< resolver_service<tcp> >

再对basic_io_object进行展开:

template <typename IoObjectService>

class basic_io_object

à

template < resolver_service<tcp> >

class basic_io_object

在basic_io_object内部展开:

typedef IoObjectService service_type;

à

typedef resolver_service<tcp> service_type;

于是,可以确定basic_io_object::service的类型为resolver_service<tcp>&;从而将io
object和下层的service关联起来。

再来看basic_io_object::service的初始化。我们来看其构造函数:

explicit basic_io_object(boost::asio::io_service&
io_service)

: service(boost::asio::use_service<IoObjectService>(io_service))

{

service.construct(implementation);

}

很明显,在构造过程中,使用use_service的返回值来初始化该service成员;我们知道,use_service会在io_service所维护的service链表中查找该类型,如果没有,就创建一个新的service实例;在此,就可以确保resolve_service<tcp>的实例已经被创建出来了,该服务就可以工作了(当然,不要忘记,该service事实上又委托了一层,而这个最底层的service实例,在此resolve_service<tcp>的构建过程中,内部再次调用use_service()创建出来了。过程如下:



除此之外,在构造函数体中,调用了service的construct函数,做进一步的初始化。(PS:是否有Symbian中的二段构造的影子呢?)

asio 的io逻辑总结

前面部分以resolver为例,分析了resolver的功能和对应service之间的关系,纵观所有的io
object,都是采用了这种模式,总结起来有如下几点:

·
asio提供了多个basic_ 模版类。

· 应用层使用对应的basic_
模版类的typedef的具体类,对外提供服务接口。

·
io object内部,将操作委托给底层服务类。

· 底层服务类再次将操作委托给平台实现层,完成实际的工作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: