Boost Asio介绍
本文最后更新于:December 1, 2021 am
博文主要参考了Boost
官网中关于Asio-Anatomy
的文档,笔者对文档进行了翻译理解和整合。
题外话
关于NIO和ASIO的区别,可以简单地理解为
NIO通知Programmer事件就绪状态,数据从内核到用户空间的拷贝、以及后续对数据的操纵,需要Programmer手动进行,并且这个过程会阻塞线程。
ASIO中,发起请求前Programmer首先指定回调函数,内核负责准备数据和将数据拷贝到用户空间,并且调用指定的回调函数操纵数据。
总览
Asio
可以同时支持同步I/O和异步I/O。 以对socket
执行connect
的同步和异步过程举例,说明Asio
涉及了哪些类,以及它们如何工作。
核心概念介绍
boost::asio::io_conetxt io_context_obj
被称作程序和操作系统I/O设备的连接点link
。
Your program will have at least one io_context object. The io_context represents your program‘s link to the operating system‘s I/O services.
为了执行I/O操作,还需要申请一个I/O对象,比如一个TCP的Socket。我们在创建对象时将刚刚拿到的context对象传入。
boost::asio::ip::tcp::socket socket(io_context_obj);
同步过程
程序通过调用
socket
对象的connect
方法,初始化connect
操作I/O对象
socket
将请求转发forward
到io_context
上io_context
发起系统调用OS完成过程,向
io_context
返回结果如果返回了错误,
io_context
会将错误包装成boost::system::error_code
类型的数据,并被转发给I/O对象,在此处为socket
。这种error_code
可以和一个特定的值比较,比如可以作为boolean来测试,false说明没有发生错误。根据对I/O对象调用的函数不同,会有不同的结果;如果外部传入了接受ec的左值引用,那么函数调用会置ec为返回的结果;否则会抛出异常。
1
2
3boost::system::error_code ec;
socket.connect(server_endpoint, ec);
//这样不会抛异常
异步过程
异步调用时,我们会调用socket对象的不同函数。
socket.async_connect(server_endpoint, your_completion_handler);
其中第二个参数是一个函数签名,并且在此处(socket的connect中)应该有以下形式:
void your_completion_handler(const boost::system::error_code& ec);
- I/O 对象将请求转发到
io_context
-
io_context
示意操作系统应该发起一个异步的connect
一段时间过后(在同步调用的情况下,这一段时间应该包含在connect operation中
- 操作系统将结果放在一个队列中,以供
io_context
取走 - 程序必须调用
io_context::run()
(或者其它相似功能的成员函数)来取回connect的调用结果。当有未完成的异步操作时,调用io_context::run()
会导致阻塞,因此一般情况下,当启动异步操作时,就会调用run()
。 - 在
io_context::run()
内部,io_context
将connect
的结果出队列dequeue
,转换成error_code
并且将之传入我们定义的your_completion_handler
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!