Network programs must handle adverse connection conditions; the most common is that a connected peer goes offline unexpectedly. Protocols have no way of identifying this reliably: the peer is offline after all, and unable to send a message announcing the absence. A peer can go offline for various reasons:
To determine when a peer is offline or idle, a program will implement a [@https://en.wikipedia.org/wiki/Timeout_(computing) timeout] algorithm, which closes the connection after a specified amount of time if some condition is met. For example, if no data is received for the duration. A timeout may be used to:
Traditionally, programs use a [@boost:/doc/html/boost_asio/reference/steady_timer.html `net::steady_timer`] to determine when a timeout occurs, and then call [@boost:/doc/html/boost_asio/reference/basic_socket/close/overload2.html `close`] on the socket to release the resources. The complexity of managing a separate timer is often a source of [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1269r0.html#timers frustration] for non-experts.
To simplify the handling of timeouts, these provided types wrap a [@boost:/doc/html/boost_asio/reference/basic_stream_socket.html `net::basic_stream_socket`] to provide additional features:
The `tcp_stream` is designed as a replacement for [@boost:/doc/html/boost_asio/reference/ip__tcp/socket.html `net::ip::tcp::socket`]. Any program which currently uses a socket, can switch to a `tcp_stream` and achieve the features above (although some interfaces are different, see below). Networking now allows I/O objects to construct with any instance of __ExecutionContext__ or __Executor__ objects. Here we construct a stream which uses a particular I/O context to dispatch completion handlers:
The function [@boost:/doc/html/boost_asio/reference/make_strand.html `make_strand`] returns a strand constructed from an execution context or executor. When a [@boost:/doc/html/boost_asio/reference/strand.html `net::strand`] is chosen for the stream's executor, all completion handlers which do not already have an associated executor will use the strand. This is both a notational convenience (no need for `strand::wrap` or `bind_executor` at call sites) and a measure of safety, as it is no longer possible to forget to use the strand.
Before data can be exchanged, the stream needs to be connected to a peer. The following code sets a timeout for an asynchronous connect operation. In Beast, functions to connect to a range of endpoints (such as the range returned by [@boost:/doc/html/boost_asio/reference/ip__basic_resolver/resolve/overload3.html `net::ip::tcp::resolver::resolve`]) are members of the class rather than free functions such as [@boost:/doc/html/boost_asio/reference/async_connect.html `net::async_connect`].
A server will use an acceptor bound to a particular IP address and port to listen to and receive incoming connection requests. The acceptor returns an ordinary socket. A `tcp_stream` can be move-constructed from the underlying `basic_stream_socket` thusly:
Timeouts apply to the logical operation, expressed as a series of asynchronous calls, rather than just the next call. This code reads a line from the stream and writes it back. Both the read and the write must complete within 30 seconds from when the timeout was set; the timer is not reset between operations.
Since reads and writes can take place concurrently, it is possible to have two simultaneous logical operations where each operation either only reads, or only writes. The beginning of a new read or write operation will use the most recently set timeout. This will not affect operations that are already outstanding.