基本流程剖析
Asio能用在同步和异步IO操作中,例如sockets。在使用Asio之前,请先看看下图——它将告诉你asio的核心模块以及它们是如何协作的。
当你要连接一个socket时,如果是同步操作应该如何使用。
你的程序至少应该有一个io_service对象,它表示你的程序联结到了操作系统层的IO。
asio::io_service io_service;
为了执行IO操作你的程序需要一个IO对象比如一个TCP socket。
asio::ip::tcp::socket socket(io_service);
当你的程序执行同步连接时,会执行如下的事件序列:
1、程序初始化IO对象的连接
socket.connect(server_endpoint);
2、IO对象转发业务请求给io_service。
3、io_service调用操作系统的连接操作。
4、操作系统把结果返回给io_service。
5、io_service将操作系统层级的error转化为asio::error_code,该错误码将会和一些特定的常量值比较,或者和bool型比较(当值为false时,表示没有错误),错误码比较结果最后分发给IO对象。
6、一旦IO操作失败,IO对象抛出一个asio::system_error类型的exception,我们要得到该错误码而不是抛出,做如下的初始化:
asio::error_code ec;
socket.connect(server_endpoint, ec);
这样该错误码不会被抛出,而是作为引用结果被获取。
在异步的操作中是不同的工作流。
1、你的程序通过调用IO对象实例化网络连接。
socket.async_connect(server_endpoint, your_completion_handler);
你的异步回调是一个函数或者函数对象。(译者注:此处如果为boost版本,你需要使用boost::bind来实现,而在c++11及其以上版本中,你可以轻松地使用lambda表达式解决这一问题)
void your_completion_handler(const asio::error_code& ec);
回调的函数标识取决于你的异步函数本身,在指导手册中每个都会作出说明。
2、IO对象将请求转发给io_service。
3、io_service告知操作系统需要建立一个异步连接。
时间流继续。(在同步的模型中这是被阻塞的,我们在连接过程中不能进行任何操作)
4、操作系统将连接完成的标识放在一个队列中,io_service随时准备读取队列内容。
5、你的程序必须调用io_service::run()函数以便获取到操作系统给出的结果队列,(当然相似的成员函数也可以)。一旦程序中有未完成的异步操作,该函数就是被阻塞的,(译者注:原文中使用的是block这个词,笔者认为此处的意思是run函数一直在运行的意思。)所以你一旦有了异步操作,就要尽快地调用run函数。
6、在run函数中,io_service取出队首元素,转换错误码,并且交付回调函数处理。
以上就是最简单的Asio流程,如果你还要更高级的用法,例如扩展Asio到其他异步操作,请看后文。