3_timeouts.qbk 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. [/
  2. Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. Official repository: https://github.com/boostorg/beast
  6. ]
  7. [section:timeouts Timeouts __example__]
  8. Network programs must handle adverse connection conditions; the most common
  9. is that a connected peer goes offline unexpectedly. Protocols have no way of
  10. identifying this reliably: the peer is offline after all, and unable to send
  11. a message announcing the absence. A peer can go offline for various reasons:
  12. [itemized_list
  13. [The peer experiences a power loss]
  14. [The peer becomes disconnected from the network]
  15. [The local host becomes disconnected from the network]
  16. [The network itself becomes unavailable]
  17. ]
  18. To determine when a peer is offline or idle, a program will implement a
  19. [@https://en.wikipedia.org/wiki/Timeout_(computing) timeout]
  20. algorithm, which closes the connection after a specified amount of time if
  21. some condition is met. For example, if no data is received for the duration.
  22. A timeout may be used to:
  23. [itemized_list
  24. [Drop malicious or poorly performing hosts]
  25. [Close idle connections to free up resources]
  26. [Determine if a peer is offline or no longer available]
  27. ]
  28. Traditionally, programs use a
  29. [@boost:/doc/html/boost_asio/reference/steady_timer.html `net::steady_timer`]
  30. to determine when a timeout occurs, and then call
  31. [@boost:/doc/html/boost_asio/reference/basic_socket/close/overload2.html `close`]
  32. on the socket to release the resources. The complexity of managing a separate
  33. timer is often a source of
  34. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1269r0.html#timers frustration]
  35. for non-experts.
  36. [note
  37. For portability reasons, networking does not provide timeouts
  38. or cancellation features for synchronous stream operations.
  39. ]
  40. To simplify the handling of timeouts, these provided types wrap a
  41. [@boost:/doc/html/boost_asio/reference/basic_stream_socket.html `net::basic_stream_socket`]
  42. to provide additional features:
  43. [table
  44. [[Name][Features]]
  45. [
  46. [[link beast.ref.boost__beast__tcp_stream `tcp_stream`]]
  47. [[itemized_list
  48. [Timeouts for logical operations]
  49. [[@boost:/doc/html/boost_asio/reference/ip__tcp.html `net::ip::tcp`] protocol]
  50. [[@boost:/doc/html/boost_asio/reference/executor.html `net::executor`] executor]
  51. [[link beast.ref.boost__beast__unlimited_rate_policy `unlimited_rate_policy`] rate limits]
  52. ]]
  53. ][
  54. [[link beast.ref.boost__beast__basic_stream `basic_stream`]]
  55. [[itemized_list
  56. [Timeouts for logical operations]
  57. [Configurable __Protocol__ type]
  58. [Configurable __Executor__ type]
  59. [Configurable __RatePolicy__ type]
  60. ]]
  61. ]]
  62. [/-----------------------------------------------------------------------------]
  63. [heading Construction]
  64. The `tcp_stream` is designed as a replacement for
  65. [@boost:/doc/html/boost_asio/reference/ip__tcp/socket.html `net::ip::tcp::socket`].
  66. Any program which currently uses a socket, can switch to a `tcp_stream` and achieve
  67. the features above (although some interfaces are different, see below).
  68. Networking now allows I/O objects to construct with any instance of
  69. __ExecutionContext__ or __Executor__ objects. Here we construct a stream which
  70. uses a particular I/O context to dispatch completion handlers:
  71. [code_core_3_timeouts_1]
  72. Alternatively, we can construct the stream from an executor:
  73. [code_core_3_timeouts_2]
  74. The function
  75. [@boost:/doc/html/boost_asio/reference/make_strand.html `make_strand`]
  76. returns a strand constructed from an execution context or executor. When a
  77. [@boost:/doc/html/boost_asio/reference/strand.html `net::strand`]
  78. is chosen for the stream's executor, all completion handlers which do not
  79. already have an associated executor will use the strand. This is both a
  80. notational convenience (no need for `strand::wrap` or `bind_executor` at
  81. call sites) and a measure of safety, as it is no longer possible to forget
  82. to use the strand.
  83. [code_core_3_timeouts_3]
  84. [/-----------------------------------------------------------------------------]
  85. [heading Connecting]
  86. Before data can be exchanged, the stream needs to be connected to a peer.
  87. The following code sets a timeout for an asynchronous connect operation.
  88. In Beast, functions to connect to a range of endpoints (such as the range
  89. returned by
  90. [@boost:/doc/html/boost_asio/reference/ip__basic_resolver/resolve/overload3.html `net::ip::tcp::resolver::resolve`])
  91. are members of the class rather than free functions such as
  92. [@boost:/doc/html/boost_asio/reference/async_connect.html `net::async_connect`].
  93. [code_core_3_timeouts_4]
  94. A server will use an acceptor bound to a particular IP address and port to
  95. listen to and receive incoming connection requests. The acceptor returns
  96. an ordinary socket. A `tcp_stream` can be move-constructed from the
  97. underlying `basic_stream_socket` thusly:
  98. [code_core_3_timeouts_5]
  99. [/-----------------------------------------------------------------------------]
  100. [heading Reading and Writing]
  101. Timeouts apply to the logical operation, expressed as a series of asynchronous
  102. calls, rather than just the next call. This code reads a line from the stream
  103. and writes it back. Both the read and the write must complete within 30 seconds
  104. from when the timeout was set; the timer is not reset between operations.
  105. [code_core_3_timeouts_6]
  106. Since reads and writes can take place concurrently, it is possible to have
  107. two simultaneous logical operations where each operation either only reads,
  108. or only writes. The beginning of a new read or write operation will use
  109. the most recently set timeout. This will not affect operations that are
  110. already outstanding.
  111. [code_core_3_timeouts_7]
  112. When a timeout is set, it cancels any previous read or write timeout for which
  113. no outstanding operation is in progress. Algorithms which loop over logical
  114. operations simply need to set the timeout once before the logical operation,
  115. it is not necessary to call `expires_never` in this case. Here we implement
  116. an algorithm which continuously echoes lines back, with a timeout. This example
  117. is implemented as a complete function.
  118. [code_core_3_timeouts_1f]
  119. [/-----------------------------------------------------------------------------]
  120. [heading https_get]
  121. It is important to note that all of the examples thus far which perform
  122. reads and writes with a timeout, make use of the existing networking stream
  123. algorithms. As these algorithms are written generically to work with any
  124. object meeting the stream requirements, they transparently support timeouts
  125. when used with `tcp_stream`. This can be used to enable timeouts for stream
  126. wrappers that do not currently support timeouts.
  127. The following code establishes an encrypted connection, writes an HTTP
  128. request, reads the HTTP response, and closes the connection gracefully.
  129. If these operations take longer than 30 seconds total, a timeout occurs.
  130. This code is intended to show how `tcp_stream` can be used to enable
  131. timeouts across unmodified stream algorithms which were not originally
  132. written to support timing out, and how a blocking algorithm may be written
  133. from asynchronous intermediate operations.
  134. [code_core_3_timeouts_2f]
  135. [endsect]
  136. [/-----------------------------------------------------------------------------]
  137. [section:rate_limiting Rate Limiting __example__]
  138. The
  139. [link beast.ref.boost__beast__basic_stream `basic_stream`]
  140. class template supports an additional `RatePolicy` template parameter. Objects
  141. of this type must meet the requirements of __RatePolicy__. They are used to
  142. implement rate limiting or bandwidth management. The default policy for
  143. `basic_stream` and `tcp_stream` is
  144. [link beast.ref.boost__beast__unlimited_rate_policy `unlimited_rate_policy`],
  145. which places no limits on reading and writing. The library comes with the
  146. [link beast.ref.boost__beast__simple_rate_policy `simple_rate_policy`],
  147. allowing for independent control of read and write limits expressed in terms
  148. of bytes per second. The follow code creates an instance of the basic stream
  149. with a simple rate policy, and sets the read and write limits:
  150. [code_core_3_timeouts_8]
  151. More sophisticated rate policies can be implemented as user-defined types which
  152. meet the requirements of __RatePolicy__. Here, we develop a rate policy that
  153. measures the instantaneous throughput of reads and writes. First we write a
  154. small utility class that applies an exponential smoothing function to a series
  155. of discrete rate samples, to calculate instantaneous throughput.
  156. [code_core_3_timeouts_3f]
  157. Then we define our rate policy object. We friend the type
  158. [link beast.ref.boost__beast__rate_policy_access `rate_policy_access`] to
  159. allow our implementation to be private, but still allow the `basic_stream`
  160. access to call the required functions. This lets us avoid having to write
  161. a cumbersome friend declaration for the `basic_stream` class template.
  162. Public members of rate policy objects become part of the stream object's
  163. interface, through a call to `rate_policy`.
  164. [code_core_3_timeouts_4f]
  165. To use our new policy we declare an instance of the stream, and then use it
  166. with stream algorithms as usual. At any time, we can determine the current
  167. read or write rates by calling into the policy.
  168. [code_core_3_timeouts_9]
  169. [endsect]
  170. [/-----------------------------------------------------------------------------]