Boost Asio介绍

本文最后更新于:December 1, 2021 am

博文主要参考了Boost官网中关于Asio-Anatomy的文档,笔者对文档进行了翻译理解和整合。

​ 翻译自Basic Boost.Asio Anatomy - 1.72.0

题外话

关于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);

同步过程

执行Connect的流程

  • 程序通过调用socket对象的connect方法,初始化connect操作

  • I/O对象socket将请求转发forwardio_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
      3
      boost::system::error_code ec;
      socket.connect(server_endpoint, ec);
      //这样不会抛异常

异步过程

async_op1

异步调用时,我们会调用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_contextconnect的结果出队列dequeue,转换成error_code并且将之传入我们定义的your_completion_handler

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!