Boost.Asio 可以用于对 I/O 对象(如套接字)执行同步和异步操作。在使用 Boost.Asio 之前,了解 Boost.Asio 的各个部分、您的程序以及它们如何协同工作的概念性图景可能很有用。
作为入门示例,让我们考虑一下在套接字上执行连接操作时会发生什么。我们将首先检查同步操作。
您的程序 将至少有一个 I/O 执行上下文,例如 boost::asio::io_context
对象、 boost::asio::thread_pool
对象或 boost::asio::system_context
。此 I/O 执行上下文 代表 您的程序 与 操作系统 的 I/O 服务之间的链接。
boost::asio::io_context io_context;
要执行 I/O 操作,您的程序 将需要一个 I/O 对象,例如 TCP 套接字
boost::asio::ip::tcp::socket socket(io_context);
当执行同步连接操作时,会发生以下事件序列
1. 您的程序 通过调用 I/O 对象 来启动连接操作
socket.connect(server_endpoint);
2. I/O 对象 将请求转发到 I/O 执行上下文。
3. I/O 执行上下文 调用 操作系统 来执行连接操作。
4. 操作系统 将操作结果返回给 I/O 执行上下文。
5. I/O 执行上下文 将操作产生的任何错误转换为 boost::system::error_code
类型的对象。可以将 error_code
与特定值进行比较,或者将其作为布尔值进行测试(其中 false
结果表示未发生错误)。然后,结果被转发回 I/O 对象。
6. 如果操作失败,I/O 对象 会抛出 boost::system::system_error
类型的异常。如果启动操作的代码改为写成
boost::system::error_code ec; socket.connect(server_endpoint, ec);
那么 error_code
变量 ec
将设置为操作结果,并且不会抛出异常。
当使用异步操作时,会发生不同的事件序列。
1. 您的程序 通过调用 I/O 对象 来启动连接操作
socket.async_connect(server_endpoint, your_completion_handler);
其中 your_completion_handler
是具有以下签名的函数或函数对象
void your_completion_handler(const boost::system::error_code& ec);
所需的确切签名取决于正在执行的异步操作。参考文档指示了每个操作的适当形式。
2. I/O 对象 将请求转发到 I/O 执行上下文。
3. I/O 执行上下文 向 操作系统 发出信号,表明它应该启动异步连接。
时间流逝。(在同步情况下,此等待将完全包含在连接操作的持续时间内。)
4. 操作系统 指示连接操作已完成,方法是将结果放在队列中,准备由 I/O 执行上下文 拾取。
5. 当使用 io_context
作为 I/O 执行上下文 时,您的程序 必须调用 io_context::run()
(或类似的 io_context
成员函数之一)才能检索结果。调用 io_context::run()
会在有未完成的异步操作时阻塞,因此您通常会在启动第一个异步操作后立即调用它。
6. 在调用 io_context::run()
期间,I/O 执行上下文 将操作结果出队,将其转换为 error_code
,然后将其传递给 您的完成处理程序。
这是 Boost.Asio 如何运作的简化图景。如果您的需求更高级,例如扩展 Boost.Asio 以执行其他类型的异步操作,您将需要深入研究文档。