| [/ |
| / Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
| / |
| / Distributed under the Boost Software License, Version 1.0. (See accompanying |
| / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| /] |
| |
| [section:basics Basic Boost.Asio Anatomy] |
| |
| Boost.Asio may be used to perform both synchronous and asynchronous operations on I/O |
| objects such as sockets. Before using Boost.Asio it may be useful to get a conceptual |
| picture of the various parts of Boost.Asio, your program, and how they work together. |
| |
| As an introductory example, let's consider what happens when you perform a |
| connect operation on a socket. We shall start by examining synchronous |
| operations. |
| |
| [$boost_asio/sync_op.png] |
| |
| [*Your program] will have at least one [*I/O execution context], such as an |
| `boost::asio::io_context` object, `boost::asio::thread_pool` object, or |
| `boost::asio::system_context`. This [*I/O execution context] represents [*your |
| program]'s link to the [*operating system]'s I/O services. |
| |
| boost::asio::io_context io_context; |
| |
| To perform I/O operations [*your program] will need an [*I/O object] such as a |
| TCP socket: |
| |
| boost::asio::ip::tcp::socket socket(io_context); |
| |
| When a synchronous connect operation is performed, the following sequence of |
| events occurs: |
| |
| 1. [*Your program] initiates the connect operation by calling the [*I/O |
| object]: |
| |
| socket.connect(server_endpoint); |
| |
| 2. The [*I/O object] forwards the request to the [*I/O execution context]. |
| |
| 3. The [*I/O execution context] calls on the [*operating system] to perform the |
| connect operation. |
| |
| 4. The [*operating system] returns the result of the operation to the |
| [*I/O execution context]. |
| |
| 5. The [*I/O execution context] translates any error resulting from the |
| operation into an object of type `boost::system::error_code`. An `error_code` may be |
| compared with specific values, or tested as a boolean (where a `false` result |
| means that no error occurred). The result is then forwarded back up to the |
| [*I/O object]. |
| |
| 6. The [*I/O object] throws an exception of type `boost::system::system_error` if the |
| operation failed. If the code to initiate the operation had instead been |
| written as: |
| |
| boost::system::error_code ec; |
| socket.connect(server_endpoint, ec); |
| |
| then the `error_code` variable `ec` would be set to the result of the |
| operation, and no exception would be thrown. |
| |
| When an asynchronous operation is used, a different sequence of events occurs. |
| |
| [$boost_asio/async_op1.png] |
| |
| 1. [*Your program] initiates the connect operation by calling the [*I/O |
| object]: |
| |
| socket.async_connect(server_endpoint, your_completion_handler); |
| |
| where `your_completion_handler` is a function or function object with the |
| signature: |
| |
| void your_completion_handler(const boost::system::error_code& ec); |
| |
| The exact signature required depends on the asynchronous operation being |
| performed. The reference documentation indicates the appropriate form for each |
| operation. |
| |
| 2. The [*I/O object] forwards the request to the [*I/O execution context]. |
| |
| 3. The [*I/O execution context] signals to the [*operating system] that it |
| should start an asynchronous connect. |
| |
| Time passes. (In the synchronous case this wait would have been contained |
| entirely within the duration of the connect operation.) |
| |
| [$boost_asio/async_op2.png] |
| |
| 4. The [*operating system] indicates that the connect operation has completed |
| by placing the result on a queue, ready to be picked up by the [*I/O execution |
| context]. |
| |
| 5. When using an `io_context` as the [*I/O execution context], [*your program] |
| must make a call to `io_context::run()` (or to one of the similar `io_context` |
| member functions) in order for the result to be retrieved. A call to |
| `io_context::run()` blocks while there are unfinished asynchronous operations, |
| so you would typically call it as soon as you have started your first |
| asynchronous operation. |
| |
| 6. While inside the call to `io_context::run()`, the [*I/O execution context] |
| dequeues the result of the operation, translates it into an `error_code`, and |
| then passes it to [*your completion handler]. |
| |
| This is a simplified picture of how Boost.Asio operates. You will want to delve |
| further into the documentation if your needs are more advanced, such as |
| extending Boost.Asio to perform other types of asynchronous operations. |
| |
| [endsect] |