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

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

2013-05-23 14:04 281 查看
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 <typenameResolveHandler>
void
async_resolve(constquery&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;

returnthis->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
<typenameHandler>
void async_resolve(implementation_type&impl,
constquery_type&query,Handlerhandler)
{
//
Allocate and construct an operation to wrap the handler.
typedefresolve_op<Protocol,Handler>op;
typenameop::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内部,将操作委托给底层服务类。
· 底层服务类再次将操作委托给平台实现层,完成实际的工作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: