mirror of
https://github.com/boostorg/beast.git
synced 2025-08-06 00:04:50 +02:00
Doc work
This commit is contained in:
@@ -3,6 +3,7 @@ Version 208:
|
|||||||
* Add get_lowest_layer free function
|
* Add get_lowest_layer free function
|
||||||
* Add lowest_layer_type metafunction
|
* Add lowest_layer_type metafunction
|
||||||
* Add close_socket, beast_close_socket customization
|
* Add close_socket, beast_close_socket customization
|
||||||
|
* Doc work
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@@ -111,6 +111,12 @@
|
|||||||
[def __flat_static_buffer_base__ [link beast.ref.boost__beast__flat_static_buffer_base `flat_static_buffer_base`]]
|
[def __flat_static_buffer_base__ [link beast.ref.boost__beast__flat_static_buffer_base `flat_static_buffer_base`]]
|
||||||
[def __websocket_stream__ [link beast.ref.boost__beast__websocket__stream `websocket::stream`]]
|
[def __websocket_stream__ [link beast.ref.boost__beast__websocket__stream `websocket::stream`]]
|
||||||
|
|
||||||
|
[/
|
||||||
|
VFALCO unfortunately quickbook wants relative paths and we have no
|
||||||
|
variables so all of the .cpp and .hpp files are placed here to keep
|
||||||
|
the paths close to absolute.
|
||||||
|
]
|
||||||
|
|
||||||
[import ../../example/common/detect_ssl.hpp]
|
[import ../../example/common/detect_ssl.hpp]
|
||||||
[import ../../example/doc/http_examples.hpp]
|
[import ../../example/doc/http_examples.hpp]
|
||||||
[import ../../example/echo-op/echo_op.cpp]
|
[import ../../example/echo-op/echo_op.cpp]
|
||||||
@@ -121,18 +127,20 @@
|
|||||||
|
|
||||||
[import ../../test/doc/exemplars.cpp]
|
[import ../../test/doc/exemplars.cpp]
|
||||||
[import ../../test/doc/core_snippets.cpp]
|
[import ../../test/doc/core_snippets.cpp]
|
||||||
[import ../../test/doc/core_3_layers.cpp]
|
|
||||||
[import ../../test/doc/http_snippets.cpp]
|
[import ../../test/doc/http_snippets.cpp]
|
||||||
[import ../../test/doc/websocket_snippets.cpp]
|
[import ../../test/doc/websocket_snippets.cpp]
|
||||||
|
|
||||||
[include 01_intro.qbk]
|
[import ../../test/doc/core_1_refresher.cpp]
|
||||||
[include 02_examples.qbk]
|
[import ../../test/doc/core_3_layers.cpp]
|
||||||
[include 03_core.qbk]
|
|
||||||
[include 04_http.qbk]
|
[include 01_intro/0_intro.qbk]
|
||||||
[include 05_http_examples.qbk]
|
[include 02_examples/0_examples.qbk]
|
||||||
[include 06_websocket.qbk]
|
[include 03_core/0_core.qbk]
|
||||||
[include 07_concepts.qbk]
|
[include 04_http/0_http.qbk]
|
||||||
[include 08_design.qbk]
|
[include 05_http_examples/0_http_examples.qbk]
|
||||||
|
[include 06_websocket/0_websocket.qbk]
|
||||||
|
[include 07_concepts/0_concepts.qbk]
|
||||||
|
[include 08_design/0_design.qbk]
|
||||||
[include 09_releases.qbk]
|
[include 09_releases.qbk]
|
||||||
|
|
||||||
[section:quickref Reference]
|
[section:quickref Reference]
|
||||||
|
@@ -137,4 +137,4 @@ for his generous participation and source code contributions.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[include 01_intro/1_reports.qbk]
|
[include 1_reports.qbk]
|
@@ -9,17 +9,14 @@
|
|||||||
|
|
||||||
[section:using_io Using Networking]
|
[section:using_io Using Networking]
|
||||||
|
|
||||||
This library depends and builds on the networking facilities destined to become
|
This library uses the
|
||||||
part of the official C++ standard library. The latest draft of the proposal to
|
[@http://cplusplus.github.io/networking-ts/draft.pdf Networking Technical Specification],
|
||||||
add these networking facilities is called the
|
scheduled to become an official part of C++ no sooner than the year
|
||||||
[@http://cplusplus.github.io/networking-ts/draft.pdf Networking Technical Specification].
|
2023. Three implementations exist, with cosmetic differences but
|
||||||
This specification is projected to become official no sooner than the year
|
otherwise using the same function signatures and type declarations:
|
||||||
2023. There are three implementations of this specification, which differ
|
Boost.Asio, stand-alone Asio, and networking-ts-impl. This table shows
|
||||||
cosmetically but otherwise use the same function signatures and type
|
how a variable of the each library's `io_context` type is declared by
|
||||||
declarations: the reference networking-ts implementation, the Boost.Asio
|
including the appropriate header and using a suitable namespace alias:
|
||||||
implementation, and the stand-alone Asio implementation. The following
|
|
||||||
table illustrates shows how an I/O context variable is declared by including
|
|
||||||
the appropriate header and using a suitable namespace alias:
|
|
||||||
|
|
||||||
[table Networking Implementations
|
[table Networking Implementations
|
||||||
[[Name][Namespace and Header Example ]]
|
[[Name][Namespace and Header Example ]]
|
||||||
@@ -54,31 +51,31 @@ the appropriate header and using a suitable namespace alias:
|
|||||||
]
|
]
|
||||||
|
|
||||||
This document refers to the three implementations above interchangeably and
|
This document refers to the three implementations above interchangeably and
|
||||||
collectively as "networking." The Boost.Asio and Asio flavors of networking
|
collectively as [*Networking] (or just ['networking]). The Boost.Asio and
|
||||||
provide additional functionality which is not currently proposed for C++ (but
|
Asio flavors of Networking provide additional features not currently proposed
|
||||||
will likely appear in a future specification). Examples of functionality
|
for C++, but likely to appear in a future specification, such as:
|
||||||
in Boost.Asio not present in the proposed networking draft include support for:
|
|
||||||
|
|
||||||
* [@boost:/doc/html/boost_asio/reference/serial_port.html Serial ports]
|
* [@boost:/doc/html/boost_asio/reference/serial_port.html Serial ports]
|
||||||
* [@boost:/doc/html/boost_asio/reference/local__stream_protocol.html UNIX domain sockets]
|
* [@boost:/doc/html/boost_asio/reference/local__stream_protocol.html UNIX domain sockets]
|
||||||
* [@boost:/doc/html/boost_asio/reference/signal_set.html POSIX signals] (e.g. SIGINT, SIGABORT)
|
* [@boost:/doc/html/boost_asio/reference/signal_set.html POSIX signals] (e.g. SIGINT, SIGABORT)
|
||||||
* [@boost:/doc/html/boost_asio/reference/ssl__stream.html TLS streams] (such as OpenSSL)
|
* [@boost:/doc/html/boost_asio/reference/ssl__stream.html TLS streams] (such as OpenSSL)
|
||||||
|
|
||||||
|
Boost.Beast depends specifically on the Boost.Asio flavor of Networking,
|
||||||
|
although this may change in the future.
|
||||||
|
While this library offers performant implementations of the HTTP and
|
||||||
|
WebSocket network protocols, it depends on the networking interfaces
|
||||||
|
to perform general tasks such as performing domain name resolution
|
||||||
|
(DNS lookup), establishing outgoing connections, and accepting incoming
|
||||||
|
connections. Callers are responsible for interacting with networking
|
||||||
|
to initialize objects to the correct state where they are usable by
|
||||||
|
this library.
|
||||||
|
|
||||||
In this documentation, the example code, and the implementation, the `net`
|
In this documentation, the example code, and the implementation, the `net`
|
||||||
namespace is used to qualify networking identifiers. For Boost.Beast,
|
namespace is used to qualify Networking identifiers. For Boost.Beast,
|
||||||
`net` will be an alias for the `boost::asio` namespace.
|
`net` will be an alias for the `boost::asio` namespace.
|
||||||
|
|
||||||
While this library offers performant implementations of the HTTP and
|
To further ease of use, this library provides an extensive collection
|
||||||
WebSocket network protocols, it depends on the networking interface
|
of types and algorithms. This section of the documentation explains these types and algorithms, provides examples
|
||||||
to perform tasks which are not specific to the protocol. Examples of
|
|
||||||
these tasks include performing domain name resolution (DNS lookup),
|
|
||||||
establishing outgoing connections, and accepting incoming connections.
|
|
||||||
Callers are responsible for interacting with networking to initialize
|
|
||||||
objects to the correct state where they are usable by this library.
|
|
||||||
|
|
||||||
To facilitiate interacting with networking, the library provides an
|
|
||||||
extensive collection of types and algorithms. This section of the
|
|
||||||
documentation explains these types and algorithms, provides examples
|
|
||||||
of usage, and also provides refreshers and tutorials for working with
|
of usage, and also provides refreshers and tutorials for working with
|
||||||
networking.
|
networking.
|
||||||
|
|
||||||
@@ -92,12 +89,12 @@ effect:
|
|||||||
[snippet_core_1a]
|
[snippet_core_1a]
|
||||||
[snippet_core_1b]
|
[snippet_core_1b]
|
||||||
|
|
||||||
[include 03_core/1_refresher.qbk]
|
[include 1_refresher.qbk]
|
||||||
[include 03_core/2_streams.qbk]
|
[include 2_streams.qbk]
|
||||||
[include 03_core/3_layers.qbk]
|
[include 3_layers.qbk]
|
||||||
[include 03_core/4_buffers.qbk]
|
[include 4_buffers.qbk]
|
||||||
[include 03_core/5_files.qbk]
|
[include 5_files.qbk]
|
||||||
[include 03_core/6_composed.qbk]
|
[include 6_composed.qbk]
|
||||||
[include 03_core/7_detect_ssl.qbk]
|
[include 7_detect_ssl.qbk]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
@@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
[section:asio_refresher Refresher]
|
[section:asio_refresher Refresher]
|
||||||
|
|
||||||
To use Beast effectively, a prior understanding of networking is required.
|
To use Beast effectively, a prior understanding of Networking is required.
|
||||||
This section reviews networking concepts as a reminder and guide for further
|
This section reviews these concepts as a reminder and guide for further
|
||||||
learning.
|
learning.
|
||||||
|
|
||||||
A
|
A
|
||||||
@@ -44,46 +44,37 @@ interact with networking using various flavors of interfaces such as
|
|||||||
[@https://en.wikipedia.org/wiki/Berkeley_sockets ['Berkeley sockets]] or
|
[@https://en.wikipedia.org/wiki/Berkeley_sockets ['Berkeley sockets]] or
|
||||||
[@https://en.wikipedia.org/wiki/Winsock ['Windows Sockets 2]] ("Winsock").
|
[@https://en.wikipedia.org/wiki/Winsock ['Windows Sockets 2]] ("Winsock").
|
||||||
|
|
||||||
C++ Networking, represented by __NetTS__ and __Asio__, provides another layer
|
Networking in C++, represented by __Asio__,
|
||||||
of abstraction with features such as:
|
[@https://think-async.com/Asio/ Asio], and
|
||||||
|
__NetTS__, provides a layer of abstraction to interact portably with the
|
||||||
|
operating system facilities for not just networking but general
|
||||||
|
[@https://en.wikipedia.org/wiki/Input/output ['input/output]] ("I/O").
|
||||||
|
|
||||||
* Deadline timers
|
[/-----------------------------------------------------------------------------]
|
||||||
* Buffer sequences
|
|
||||||
* Stream concepts
|
|
||||||
* Asynchronous I/O
|
|
||||||
|
|
||||||
These concepts enable generic programming so that higher levels of abstraction
|
|
||||||
may be composed to arbitrary degree. In fact, the interfaces and concepts
|
|
||||||
offered by networking are best described as providing support for general
|
|
||||||
[@https://en.wikipedia.org/wiki/Input/output ['input/output]] ("I/O")
|
|
||||||
algorithms, including networking.
|
|
||||||
|
|
||||||
[heading Buffers]
|
[heading Buffers]
|
||||||
|
|
||||||
A
|
A
|
||||||
[@https://en.wikipedia.org/wiki/Data_buffer ['buffer]]
|
[@https://en.wikipedia.org/wiki/Data_buffer ['buffer]]
|
||||||
holds a contiguous sequence of bytes used when reading or writing data with
|
holds a contiguous sequence of bytes used when performing I/O.
|
||||||
objects that perform I/O.
|
The types
|
||||||
The networking types __const_buffer__ and __mutable_buffer__ represent
|
[@boost:/doc/html/boost_asio/reference/const_buffer.html `net::const_buffer`]
|
||||||
these memory regions as type-safe pointer/size pairs, as shown below:
|
and
|
||||||
```
|
[@boost:/doc/html/boost_asio/reference/mutable_buffer.html `net::mutable_buffer`]
|
||||||
net::const_buffer cb(string_view("Hello, world!", 13));
|
represent these memory regions as type-safe pointer/size pairs:
|
||||||
assert(string_view(reinterpret_cast<char const*>(cb.data()), cb.size()) == "Hello, world!");
|
|
||||||
|
|
||||||
char storage[13];
|
[code_core_1_refresher_1s]
|
||||||
net::mutable_buffer mb(bytes, sizeof(storage));
|
|
||||||
std::memcpy(mb.data(), cb.data(), mb.size());
|
|
||||||
assert(string_view(reinterpret_cast<char const*>(mb.data()), mb.size()) == "Hello, world!");
|
|
||||||
```
|
|
||||||
|
|
||||||
[tip
|
[tip
|
||||||
Networking uses custom buffer types because `span<byte>` does too much.
|
`const_buffer` and `mutable_buffer` are preferred over `std::span<byte>`
|
||||||
It not only type-erases the original pointer but also recasts it to a
|
and `span<byte const>` because
|
||||||
pointer-to-byte. The operating system doesn't care about this, but if
|
[@https://en.cppreference.com/w/cpp/container/span `std::span`]
|
||||||
a user wants to send and receive an array of some other type, presenting
|
does too much. It not only
|
||||||
it as an array of bytes which supports bitwise operations is unnecessary.
|
type-erases the original pointer but also recasts it to a pointer-to-byte.
|
||||||
Custom buffer types also enable networking implementations to provide
|
The operating system doesn't care about this, but if a user wants to send
|
||||||
targeted features such as
|
and receive an array of some other type, presenting it as an array of bytes
|
||||||
|
which supports bitwise operations is unnecessary. Custom buffer types also
|
||||||
|
enable implementations to provide targeted features such as
|
||||||
[@boost:/doc/html/boost_asio/overview/core/buffers.html#boost_asio.overview.core.buffers.buffer_debugging ['buffer debugging]]
|
[@boost:/doc/html/boost_asio/overview/core/buffers.html#boost_asio.overview.core.buffers.buffer_debugging ['buffer debugging]]
|
||||||
without changing the more general vocabulary types.
|
without changing the more general vocabulary types.
|
||||||
]
|
]
|
||||||
@@ -91,36 +82,71 @@ these memory regions as type-safe pointer/size pairs, as shown below:
|
|||||||
The concepts
|
The concepts
|
||||||
__ConstBufferSequence__ and __MutableBufferSequence__ describe bidirectional
|
__ConstBufferSequence__ and __MutableBufferSequence__ describe bidirectional
|
||||||
ranges whose value type is convertible to `const_buffer` and
|
ranges whose value type is convertible to `const_buffer` and
|
||||||
`mutable_buffer` respectively. Buffer sequences may be used to transact
|
`mutable_buffer` respectively. These sequences allow transacting with
|
||||||
in multiple buffers in a single function call, a technique sometimes
|
multiple buffers in a single function call, a technique called
|
||||||
referred to as
|
|
||||||
[@https://en.wikipedia.org/wiki/Vectored_I/O ['scatter/gather I/O]].
|
[@https://en.wikipedia.org/wiki/Vectored_I/O ['scatter/gather I/O]].
|
||||||
Buffers and sequences are non-owning; copies produce shallow references and
|
Buffers and buffer sequences are non-owning; copies produce shallow references
|
||||||
not duplicates of the underlying memory. Each of these statements declares
|
and not duplicates of the underlying memory. Each of these statements declares
|
||||||
a buffer sequence:
|
a buffer sequence:
|
||||||
```
|
|
||||||
net::const_buffer b1;
|
|
||||||
net::mutable_buffer b2;
|
|
||||||
std::array<net::const_buffer, 3> b3;
|
|
||||||
```
|
|
||||||
|
|
||||||
The __DynamicBuffer__ concept defines a buffer container with an interface
|
[code_core_1_refresher_2s]
|
||||||
that supports increasing and decreasing the size of the managed buffer
|
|
||||||
sequence. Beast and networking use dynamic buffers when the amount of
|
The functions
|
||||||
storage required to perform an operation is not known ahead of time,
|
[@boost:/doc/html/boost_asio/reference/buffer_size.html `net::buffer_size`] and
|
||||||
such as when reading a complete HTTP message.
|
[@boost:/doc/html/boost_asio/reference/buffer_copy.html `net::buffer_copy`]
|
||||||
|
determine the total number of bytes in a buffer sequence, and transfer some
|
||||||
|
or all of bytes from one buffer sequence to another respectively. The
|
||||||
|
function `buffer_size` is a customization point: user defined overloads
|
||||||
|
in foreign namespaces are possible, and callers should invoke `buffer_size`
|
||||||
|
without namespace qualification. The functions
|
||||||
|
[@boost:/doc/html/boost_asio/reference/buffer_sequence_begin.html `net::buffer_sequence_begin`] and
|
||||||
|
[@boost:/doc/html/boost_asio/reference/buffer_sequence_end.html `net::buffer_sequence_end`]
|
||||||
|
are used to obtain a pair of iterators for traversing the sequence.
|
||||||
|
Beast provides a set of buffer sequence types and algorithms such as
|
||||||
|
[link beast.ref.boost__beast__buffers_cat `buffers_cat`],
|
||||||
|
[link beast.ref.boost__beast__buffers_front `buffers_front`],
|
||||||
|
[link beast.ref.boost__beast__buffers_prefix `buffers_prefix`],
|
||||||
|
[link beast.ref.boost__beast__buffers_range `buffers_range`], and
|
||||||
|
[link beast.ref.boost__beast__buffers_suffix `buffers_suffix`].
|
||||||
|
This example returns the bytes in a buffer sequence as a string:
|
||||||
|
|
||||||
|
[code_core_1_refresher_1]
|
||||||
|
|
||||||
|
The __DynamicBuffer__ concept defines a resizable buffer sequence interface.
|
||||||
|
Algorithms may be expressed in terms of dynamic buffers when the memory
|
||||||
|
requirements are not known ahead of time, for example when reading an
|
||||||
|
HTTP message from a stream.
|
||||||
|
Beast provides a well-rounded collection of dynamic buffer types such as
|
||||||
|
[link beast.ref.boost__beast__buffers_adaptor `buffers_adaptor`],
|
||||||
|
[link beast.ref.boost__beast__flat_buffer `flat_buffer`],
|
||||||
|
[link beast.ref.boost__beast__multi_buffer `multi_buffer`], and
|
||||||
|
[link beast.ref.boost__beast__static_buffer `static_buffer`].
|
||||||
|
In the following function, the contents of a stream are read into a dynamic
|
||||||
|
buffer until it contains a newline character, using
|
||||||
|
[@boost:/doc/html/boost_asio/reference/buffers_iterator.html `net::buffers_iterator`]
|
||||||
|
to treat the contents of the buffer as a range of characters:
|
||||||
|
|
||||||
|
[code_core_1_refresher_2]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[/-----------------------------------------------------------------------------]
|
||||||
|
|
||||||
[heading Synchronous I/O]
|
[heading Synchronous I/O]
|
||||||
|
|
||||||
Synchronous input and output is accomplished through blocking function
|
Synchronous input and output is accomplished through blocking function
|
||||||
calls that provide the complete results of the operation upon returning.
|
calls that return with the result of the operation. Such operations typically
|
||||||
Such operations typically cannot be canceled and do not have a method for
|
cannot be canceled and do not have a method for setting a timeout. The
|
||||||
setting a timeout. The __SyncReadStream__ and __SyncWriteStream__ concepts
|
__SyncReadStream__ and __SyncWriteStream__ concepts define requirements for
|
||||||
define requirements for
|
|
||||||
['synchronous streams]:
|
['synchronous streams]:
|
||||||
a portable I/O abstraction that exchanges data using buffer sequences
|
a portable I/O abstraction that transfers data using buffer sequences to
|
||||||
to represent bytes and either `error_code` or an exception to report
|
represent bytes and either `error_code` or an exception to report any
|
||||||
any failures.
|
failures.
|
||||||
|
[@boost:/doc/html/boost_asio/reference/basic_stream_socket.html ['net::basic_stream_socket]]
|
||||||
|
is a synchronous stream commonly used to form TCP/IP connections.
|
||||||
|
User-defined types which meet the requirements are possible:
|
||||||
|
|
||||||
|
[code_core_1_refresher_3]
|
||||||
|
|
||||||
A
|
A
|
||||||
['synchronous stream algorithm]
|
['synchronous stream algorithm]
|
||||||
@@ -128,35 +154,13 @@ is written as a function template accepting a stream object meeting the
|
|||||||
named requirements for synchronous reading, writing, or both. This example
|
named requirements for synchronous reading, writing, or both. This example
|
||||||
shows an algorithm which writes text and uses exceptions to indicate errors:
|
shows an algorithm which writes text and uses exceptions to indicate errors:
|
||||||
|
|
||||||
```
|
[code_core_1_refresher_4]
|
||||||
template <class SyncWriteStream>
|
|
||||||
void hello (SyncWriteStream& stream)
|
|
||||||
{
|
|
||||||
net::const_buffer cb(string_view("Hello, world!"));
|
|
||||||
do
|
|
||||||
{
|
|
||||||
auto bytes_transferred = stream.write_some(cb); // may throw
|
|
||||||
cb += bytes_transferred; // adjust the pointer and size
|
|
||||||
}
|
|
||||||
while (cb.size() > 0);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The same algorithm may be expressed using error codes instead of exceptions:
|
The same algorithm may be expressed using error codes instead of exceptions:
|
||||||
|
|
||||||
```
|
[code_core_1_refresher_5]
|
||||||
template <class SyncWriteStream>
|
|
||||||
void hello (SyncWriteStream& stream, error_code& ec)
|
[/-----------------------------------------------------------------------------]
|
||||||
{
|
|
||||||
net::const_buffer cb(string_view("Hello, world!"));
|
|
||||||
do
|
|
||||||
{
|
|
||||||
auto bytes_transferred = stream.write_some(cb, ec);
|
|
||||||
cb += bytes_transferred; // adjust the pointer and size
|
|
||||||
}
|
|
||||||
while (cb.size() > 0 && ! ec);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[heading Asynchronous I/O]
|
[heading Asynchronous I/O]
|
||||||
|
|
||||||
@@ -164,9 +168,9 @@ An asynchronous operation begins with a call to an
|
|||||||
[@boost:/doc/html/boost_asio/reference/asynchronous_operations.html ['initiating function]],
|
[@boost:/doc/html/boost_asio/reference/asynchronous_operations.html ['initiating function]],
|
||||||
which starts the operation and returns to the caller immediately. This
|
which starts the operation and returns to the caller immediately. This
|
||||||
['outstanding]
|
['outstanding]
|
||||||
asynchronous operation continues to make progress concurrently without
|
asynchronous operation proceeds concurrently without blocking the caller.
|
||||||
blocking. When the externally observable side effects are fully established,
|
When the externally observable side effects are fully established, a movable
|
||||||
a movable function object known as a
|
function object known as a
|
||||||
[@boost:/doc/html/boost_asio/reference/CompletionHandler.html ['completion handler]]
|
[@boost:/doc/html/boost_asio/reference/CompletionHandler.html ['completion handler]]
|
||||||
provided in the initiating function call is queued for execution with the
|
provided in the initiating function call is queued for execution with the
|
||||||
results, which may include the error code and other specific information.
|
results, which may include the error code and other specific information.
|
||||||
@@ -174,32 +178,42 @@ An asynchronous operation is said to be
|
|||||||
['completed]
|
['completed]
|
||||||
after the completion handler is queued. The code that follows shows how some
|
after the completion handler is queued. The code that follows shows how some
|
||||||
text may be written to a
|
text may be written to a
|
||||||
[@boost:/doc/html/boost_asio/reference/ip__tcp/socket.html `socket`]
|
[@boost:/doc/html/boost_asio/reference/ip__tcp/socket.html `net::socket`]
|
||||||
asynchronously, invoking a lambda when the
|
asynchronously, invoking a lambda when the
|
||||||
operation is complete:
|
operation is complete:
|
||||||
```
|
|
||||||
net::async_write(sock, net::const_buffer(string_view("Hello, world!")),
|
[code_core_1_refresher_3s]
|
||||||
[](error_code ec, std::size_t bytes_transferred)
|
|
||||||
{
|
|
||||||
if(! ec)
|
|
||||||
assert(bytes_transferred == 13);
|
|
||||||
else
|
|
||||||
std::cerr << "Error: " << ec.message() << "\n";
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
Every completion handler (also referred to as a
|
Every completion handler (also referred to as a
|
||||||
[@https://en.wikipedia.org/wiki/Continuation ['continuation]])
|
[@https://en.wikipedia.org/wiki/Continuation ['continuation]])
|
||||||
has both an
|
has both an
|
||||||
[@boost:/doc/html/boost_asio/overview/core/allocation.html ['associated allocator]]
|
[@boost:/doc/html/boost_asio/overview/core/allocation.html ['associated allocator]]
|
||||||
|
returned by
|
||||||
|
[@boost:/doc/html/boost_asio/reference/get_associated_allocator.html `net::get_associated_allocator`],
|
||||||
and an
|
and an
|
||||||
[@boost:/doc/html/boost_asio/reference/associated_executor.html ['associated executor]].
|
[@boost:/doc/html/boost_asio/reference/associated_executor.html ['associated executor]]
|
||||||
The allocator may be used to obtain temporary storage (which [*must] be
|
returned by
|
||||||
deallocated before the completion handler is invoked), while the executor
|
[@boost:/doc/html/boost_asio/reference/get_associated_executor.html `net::get_associated_executor`].
|
||||||
is a cheaply copyable object providing the algorithm used to invoke the
|
These associations may be specified intrusively:
|
||||||
completion handler. Unless customized by the caller, a completion handler
|
|
||||||
defaults to using `std::allocator<void>` and the executor of the
|
[code_core_1_refresher_6]
|
||||||
corresponding I/O object.
|
|
||||||
|
Or these associations may be specified non-intrusively, by specializing
|
||||||
|
the class templates
|
||||||
|
[@boost:/doc/html/boost_asio/reference/associated_allocator.html `net::associated_allocator`]
|
||||||
|
and
|
||||||
|
[@boost:/doc/html/boost_asio/reference/associated_executor.html `net::associated_executor`].
|
||||||
|
The function
|
||||||
|
[@boost:/doc/html/boost_asio/reference/bind_executor.html `net::bind_executor`]
|
||||||
|
may be used when the caller wants to change the executor of a completion
|
||||||
|
handler.
|
||||||
|
|
||||||
|
The allocator is used by the implementation to obtain any temporary storage
|
||||||
|
necessary to perform the operation. Temporary allocations are always freed
|
||||||
|
before the completion handler is invoked. The executor is a cheaply copyable
|
||||||
|
object providing the algorithm used to invoke the completion handler. Unless
|
||||||
|
customized by the caller, a completion handler defaults to using
|
||||||
|
`std::allocator<void>` and the executor of the corresponding I/O object.
|
||||||
|
|
||||||
Networking prescribes facilities to determine the context in which
|
Networking prescribes facilities to determine the context in which
|
||||||
handlers run. Every I/O object refers to an __ExecutionContext__ for
|
handlers run. Every I/O object refers to an __ExecutionContext__ for
|
||||||
@@ -218,15 +232,10 @@ is written as a templated initiating function template accepting a stream
|
|||||||
object meeting the named requirements for asynchronous reading, writing, or
|
object meeting the named requirements for asynchronous reading, writing, or
|
||||||
both. This example shows an algorithm which writes some text to an
|
both. This example shows an algorithm which writes some text to an
|
||||||
asynchronous stream:
|
asynchronous stream:
|
||||||
```
|
|
||||||
template <class AsyncWriteStream, class WriteHandler>
|
[code_core_1_refresher_7]
|
||||||
void async_hello (AsyncWriteStream& stream, WriteHandler&& handler)
|
|
||||||
{
|
[/-----------------------------------------------------------------------------]
|
||||||
net::async_write (stream,
|
|
||||||
net::buffer(string_view("Hello, world!")),
|
|
||||||
std::forward<Handler>(handler));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[heading Concurrency]
|
[heading Concurrency]
|
||||||
|
|
||||||
@@ -245,42 +254,57 @@ without explicit locking by requiring all access to I/O objects to be
|
|||||||
performed within a
|
performed within a
|
||||||
[@boost:/doc/html/boost_asio/overview/core/strands.html ['strand]].
|
[@boost:/doc/html/boost_asio/overview/core/strands.html ['strand]].
|
||||||
|
|
||||||
[heading Asynchronous Model]
|
[/-----------------------------------------------------------------------------]
|
||||||
|
|
||||||
Completion handlers are native to networking but cause an inversion of the
|
[heading Universal Model]
|
||||||
flow of control. Alternatives to using completion handlers include futures,
|
|
||||||
fibers, coroutines, or user-defined types. Networking supports these
|
|
||||||
alternatives with a feature that provides these hooks for customizing
|
|
||||||
initiating functions:
|
|
||||||
|
|
||||||
* Converting a custom ['CompletionToken] to a "real" handler type
|
Because completion handlers cause an inversion of the flow of control,
|
||||||
|
sometimes other methods of attaching a continuation are desired. Networking
|
||||||
|
provides the
|
||||||
|
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3747.pdf ['Universal Model for Asynchronous Operations]],
|
||||||
|
providing a customizable means for transforming the signature of the initiating
|
||||||
|
function to use other types of objects and methods in place of a completion
|
||||||
|
handler callback. For example to call to write a string to a socket
|
||||||
|
asynchronously, using a `std::future` to receive the number of bytes transferred
|
||||||
|
thusly looks like this:
|
||||||
|
|
||||||
* Creating the initiating function's result
|
[code_core_1_refresher_4s]
|
||||||
|
|
||||||
|
This functionality is enabled by passing the variable
|
||||||
|
[@boost:/doc/html/boost_asio/reference/use_future.html `net::use_future`]
|
||||||
|
(of type
|
||||||
|
[@boost:/doc/html/boost_asio/reference/use_future_t.html `net::use_future_t<>`])
|
||||||
|
in place of the completion handler. The same `async_write` function overload
|
||||||
|
can work with a
|
||||||
|
[@https://en.wikipedia.org/wiki/Fiber_(computer_science) ['fiber]]
|
||||||
|
launched with
|
||||||
|
[@boost:/doc/html/boost_asio/reference/spawn/overload1.html `net::spawn`]:
|
||||||
|
|
||||||
|
[code_core_1_refresher_5s]
|
||||||
|
|
||||||
|
In both of these cases, an object with a specific type is used in place of
|
||||||
|
the completion handler, and the return value of the initiating function
|
||||||
|
is transformed from `void` to `std::future<std::size_t>` or `std::size_t`.
|
||||||
|
The return type transformation is supported by customization points in the
|
||||||
|
initiating function signature. Here is the signature for `net::async_write`:
|
||||||
|
|
||||||
|
[code_core_1_refresher_8]
|
||||||
|
|
||||||
[/
|
The type of the function's return value is determined by the
|
||||||
The system
|
[@boost:/doc/html/boost_asio/reference/async_result.html `net::async_result`]
|
||||||
for customizing the return type of initiating functions and obtaining the
|
customization point, which comes with specializations for common library
|
||||||
actual completion handler from a completion token is known as the
|
types such as `std::future` and may also be specialized for user-defined
|
||||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3747.pdf ['Universal Model for Asynchronous Operations]] (N3747).
|
types. The universal model also provides the
|
||||||
This generic example shows the signature for an initiating function to
|
[@boost:/doc/html/boost_asio/reference/async_completion.html `net::async_completion`]
|
||||||
write some text to a stream:
|
customization point for transforming
|
||||||
```
|
the `handler` argument (called a
|
||||||
template <class AsyncWriteStream, class WriteHandler>
|
[@boost:/doc/html/boost_asio/reference/asynchronous_operations/completion_token.html ['CompletionToken]]
|
||||||
auto async_hello (AsyncWriteStream& stream, WriteHandler&& handler);
|
in this context) into an underlying completion handler to be invoked when the
|
||||||
```
|
operation is complete. This transformed, internal handler is responsible for
|
||||||
|
the finalizing step that delivers the result of the operation to the caller.
|
||||||
The signature for the initiating function includes a
|
For example, when using `net::use_future` the internal handler will deliver
|
||||||
['completion token],
|
the result by calling `std::promise::set_value` on the promise object
|
||||||
which is a generalization of completion handlers permitting user-defined
|
returned by the initiating function.
|
||||||
types such as futures or coroutines to be substituted as the mechanism by
|
|
||||||
which the results of the asynchronous operation are delivered. The following
|
|
||||||
statements all call the same function to asynchronously read data from a
|
|
||||||
stream, but use a different method for receiving the results:
|
|
||||||
]
|
|
||||||
|
|
||||||
[/-----------------------------------------------------------------------------]
|
[/-----------------------------------------------------------------------------]
|
||||||
|
|
||||||
|
@@ -198,15 +198,15 @@ parts of the implementation. The layers are arranged thusly:
|
|||||||
[http_snippet_1]
|
[http_snippet_1]
|
||||||
]
|
]
|
||||||
|
|
||||||
[include 04_http/01_primer.qbk]
|
[include 01_primer.qbk]
|
||||||
[include 04_http/02_message.qbk]
|
[include 02_message.qbk]
|
||||||
[include 04_http/03_streams.qbk]
|
[include 03_streams.qbk]
|
||||||
[include 04_http/04_serializer_streams.qbk]
|
[include 04_serializer_streams.qbk]
|
||||||
[include 04_http/05_parser_streams.qbk]
|
[include 05_parser_streams.qbk]
|
||||||
[include 04_http/06_serializer_buffers.qbk]
|
[include 06_serializer_buffers.qbk]
|
||||||
[include 04_http/07_parser_buffers.qbk]
|
[include 07_parser_buffers.qbk]
|
||||||
[include 04_http/08_chunked_encoding.qbk]
|
[include 08_chunked_encoding.qbk]
|
||||||
[include 04_http/09_custom_body.qbk]
|
[include 09_custom_body.qbk]
|
||||||
[include 04_http/10_custom_parsers.qbk]
|
[include 10_custom_parsers.qbk]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
@@ -29,13 +29,13 @@ Boost.Asio with a consistent asynchronous model using a modern C++ approach.
|
|||||||
[ws_snippet_1]
|
[ws_snippet_1]
|
||||||
]
|
]
|
||||||
|
|
||||||
[include 06_websocket/01_streams.qbk]
|
[include 01_streams.qbk]
|
||||||
[include 06_websocket/02_connect.qbk]
|
[include 02_connect.qbk]
|
||||||
[include 06_websocket/03_client.qbk]
|
[include 03_client.qbk]
|
||||||
[include 06_websocket/04_server.qbk]
|
[include 04_server.qbk]
|
||||||
[include 06_websocket/05_messages.qbk]
|
[include 05_messages.qbk]
|
||||||
[include 06_websocket/06_control.qbk]
|
[include 06_control.qbk]
|
||||||
[include 06_websocket/07_teardown.qbk]
|
[include 07_teardown.qbk]
|
||||||
[include 06_websocket/08_notes.qbk]
|
[include 08_notes.qbk]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
@@ -11,14 +11,14 @@
|
|||||||
|
|
||||||
This section describes all of the concepts defined by the library.
|
This section describes all of the concepts defined by the library.
|
||||||
|
|
||||||
[include 07_concepts/Body.qbk]
|
[include Body.qbk]
|
||||||
[include 07_concepts/BodyReader.qbk]
|
[include BodyReader.qbk]
|
||||||
[include 07_concepts/BodyWriter.qbk]
|
[include BodyWriter.qbk]
|
||||||
[include 07_concepts/BufferSequence.qbk]
|
[include BufferSequence.qbk]
|
||||||
[include 07_concepts/DynamicBuffer.qbk]
|
[include DynamicBuffer.qbk]
|
||||||
[include 07_concepts/Fields.qbk]
|
[include Fields.qbk]
|
||||||
[include 07_concepts/FieldsWriter.qbk]
|
[include FieldsWriter.qbk]
|
||||||
[include 07_concepts/File.qbk]
|
[include File.qbk]
|
||||||
[include 07_concepts/Streams.qbk]
|
[include Streams.qbk]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
@@ -66,9 +66,9 @@ interfaces of Beast (which have since changed).
|
|||||||
</mediaobject>
|
</mediaobject>
|
||||||
''']
|
''']
|
||||||
|
|
||||||
[include 08_design/1_http_message.qbk]
|
[include 1_http_message.qbk]
|
||||||
[include 08_design/2_http_comparison.qbk]
|
[include 2_http_comparison.qbk]
|
||||||
[include 08_design/3_websocket_zaphoyd.qbk]
|
[include 3_websocket_zaphoyd.qbk]
|
||||||
[include 08_design/4_faq.qbk]
|
[include 4_faq.qbk]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
@@ -17,9 +17,11 @@ add_executable (tests-doc
|
|||||||
${EXTRAS_FILES}
|
${EXTRAS_FILES}
|
||||||
${TEST_MAIN}
|
${TEST_MAIN}
|
||||||
Jamfile
|
Jamfile
|
||||||
|
snippets.hpp
|
||||||
snippets.ipp
|
snippets.ipp
|
||||||
core_examples.cpp
|
core_examples.cpp
|
||||||
core_snippets.cpp
|
core_snippets.cpp
|
||||||
|
core_1_refresher.cpp
|
||||||
core_3_layers.cpp
|
core_3_layers.cpp
|
||||||
http_examples.cpp
|
http_examples.cpp
|
||||||
http_snippets.cpp
|
http_snippets.cpp
|
||||||
|
@@ -20,6 +20,7 @@ alias run-tests :
|
|||||||
[ compile http_snippets.cpp ]
|
[ compile http_snippets.cpp ]
|
||||||
[ compile websocket_snippets.cpp ]
|
[ compile websocket_snippets.cpp ]
|
||||||
[ run core_examples.cpp $(TEST_MAIN) ]
|
[ run core_examples.cpp $(TEST_MAIN) ]
|
||||||
|
[ run core_1_refresher.cpp $(TEST_MAIN) ]
|
||||||
[ run core_3_layers.cpp $(TEST_MAIN) ]
|
[ run core_3_layers.cpp $(TEST_MAIN) ]
|
||||||
[ run http_examples.cpp $(TEST_MAIN) ]
|
[ run http_examples.cpp $(TEST_MAIN) ]
|
||||||
;
|
;
|
||||||
@@ -27,6 +28,7 @@ alias run-tests :
|
|||||||
exe fat-tests :
|
exe fat-tests :
|
||||||
$(TEST_MAIN)
|
$(TEST_MAIN)
|
||||||
core_examples.cpp
|
core_examples.cpp
|
||||||
|
core_1_refresher.cpp
|
||||||
core_3_layers.cpp
|
core_3_layers.cpp
|
||||||
http_examples.cpp
|
http_examples.cpp
|
||||||
;
|
;
|
||||||
|
347
test/doc/core_1_refresher.cpp
Normal file
347
test/doc/core_1_refresher.cpp
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail 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)
|
||||||
|
//
|
||||||
|
// Official repository: https://github.com/boostorg/beast
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "snippets.hpp"
|
||||||
|
|
||||||
|
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||||
|
#include <boost/beast/_experimental/test/stream.hpp>
|
||||||
|
#include <boost/beast/core/flat_buffer.hpp>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/asio/buffers_iterator.hpp>
|
||||||
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
#include <boost/asio/spawn.hpp>
|
||||||
|
#include <boost/asio/use_future.hpp>
|
||||||
|
#include <boost/asio/write.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void
|
||||||
|
snippets()
|
||||||
|
{
|
||||||
|
#include "snippets.ipp"
|
||||||
|
{
|
||||||
|
//[code_core_1_refresher_1s
|
||||||
|
net::const_buffer cb("Hello, world!", 13);
|
||||||
|
assert(string_view(reinterpret_cast<char const*>(
|
||||||
|
cb.data()), cb.size()) == "Hello, world!");
|
||||||
|
|
||||||
|
char storage[13];
|
||||||
|
net::mutable_buffer mb(storage, sizeof(storage));
|
||||||
|
std::memcpy(mb.data(), cb.data(), mb.size());
|
||||||
|
assert(string_view(reinterpret_cast<char const*>(
|
||||||
|
mb.data()), mb.size()) == "Hello, world!");
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//[code_core_1_refresher_2s
|
||||||
|
net::const_buffer b1; // a ConstBufferSequence by definition
|
||||||
|
net::mutable_buffer b2; // a MutableBufferSequence by definition
|
||||||
|
std::array<net::const_buffer, 3> b3; // A ConstBufferSequence by named requirements
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//[code_core_1_refresher_3s
|
||||||
|
// initiate an asynchronous write operation
|
||||||
|
net::async_write(sock, net::const_buffer("Hello, world!", 13),
|
||||||
|
[](error_code ec, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
// this lambda is invoked when the write operation completes
|
||||||
|
if(! ec)
|
||||||
|
assert(bytes_transferred == 13);
|
||||||
|
else
|
||||||
|
std::cerr << "Error: " << ec.message() << "\n";
|
||||||
|
});
|
||||||
|
// meanwhile, the operation is outstanding and execution continues from here
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//[code_core_1_refresher_4s
|
||||||
|
std::future<std::size_t> f = net::async_write(sock,
|
||||||
|
net::const_buffer("Hello, world!", 13), net::use_future);
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//[code_core_1_refresher_5s
|
||||||
|
net::spawn(
|
||||||
|
[&sock](net::yield_context yield)
|
||||||
|
{
|
||||||
|
std::size_t bytes_transferred = net::async_write(sock,
|
||||||
|
net::const_buffer("Hello, world!", 13), yield);
|
||||||
|
(void)bytes_transferred;
|
||||||
|
});
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//[code_core_1_refresher_1
|
||||||
|
template <class ConstBufferSequence>
|
||||||
|
std::string string_from_buffers (ConstBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
// check that the type meets the requirements using the provided type traits
|
||||||
|
static_assert(
|
||||||
|
net::is_const_buffer_sequence<ConstBufferSequence>::value,
|
||||||
|
"ConstBufferSequence requirements not met");
|
||||||
|
|
||||||
|
// optimization: reserve all the space for the string first
|
||||||
|
std::string result;
|
||||||
|
using net::buffer_size; // buffer_size is a customization point,
|
||||||
|
result.reserve(buffer_size(buffers)); // called without namespace qualification
|
||||||
|
|
||||||
|
// iterate over each buffer in the sequence and append it to the string
|
||||||
|
for(auto it = net::buffer_sequence_begin(buffers); // returns an iterator to beginning of the sequence
|
||||||
|
it != net::buffer_sequence_end(buffers);) // returns a past-the-end iterator to the sequence
|
||||||
|
{
|
||||||
|
// A buffer sequence iterator's value_type is always convertible to net::const_buffer
|
||||||
|
net::const_buffer buffer = *it++;
|
||||||
|
|
||||||
|
// A cast is always required to out-out of type-safety
|
||||||
|
result.append(static_cast<char const*>(buffer.data()), buffer.size());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
//]
|
||||||
|
|
||||||
|
//[code_core_1_refresher_2
|
||||||
|
// Read a line ending in '\n' from a socket, returning
|
||||||
|
// the number of characters up to but not including the newline
|
||||||
|
template <class DynamicBuffer>
|
||||||
|
std::size_t read_line(net::ip::tcp::socket& sock, DynamicBuffer& buffer)
|
||||||
|
{
|
||||||
|
// this alias keeps things readable
|
||||||
|
using range = net::buffers_iterator<
|
||||||
|
typename DynamicBuffer::const_buffers_type>;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
// get iterators representing the range of characters in the buffer
|
||||||
|
auto begin = range::begin(buffer.data());
|
||||||
|
auto end = range::end(buffer.data());
|
||||||
|
|
||||||
|
// search for "\n" and return if found
|
||||||
|
auto pos = std::find(begin, end, '\n');
|
||||||
|
if(pos != range::end(buffer.data()))
|
||||||
|
return std::distance(begin, end);
|
||||||
|
|
||||||
|
// Determine the number of bytes to read,
|
||||||
|
// using available capacity in the buffer first.
|
||||||
|
std::size_t bytes_to_read = std::min<std::size_t>(
|
||||||
|
std::max<std::size_t>(512, // under 512 is too little,
|
||||||
|
buffer.capacity() - buffer.size()),
|
||||||
|
std::min<std::size_t>(65536, // and over 65536 is too much.
|
||||||
|
buffer.max_size() - buffer.size()));
|
||||||
|
|
||||||
|
// Read up to bytes_to_read bytes into the dynamic buffer
|
||||||
|
buffer.commit(sock.read_some(buffer.prepare(bytes_to_read)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//]
|
||||||
|
|
||||||
|
//[code_core_1_refresher_3
|
||||||
|
// Meets the requirements of SyncReadStream
|
||||||
|
struct sync_read_stream
|
||||||
|
{
|
||||||
|
// Returns the number of bytes read upon success, otherwise throws an exception
|
||||||
|
template <class MutableBufferSequence>
|
||||||
|
std::size_t read_some(MutableBufferSequence const& buffers);
|
||||||
|
|
||||||
|
// Returns the number of bytes read successfully, sets the error code if a failure occurs
|
||||||
|
template <class MutableBufferSequence>
|
||||||
|
std::size_t read_some(MutableBufferSequence const& buffers, error_code& ec);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Meets the requirements of SyncWriteStream
|
||||||
|
struct sync_write_stream
|
||||||
|
{
|
||||||
|
// Returns the number of bytes written upon success, otherwise throws an exception
|
||||||
|
template <class ConstBufferSequence>
|
||||||
|
std::size_t write_some(ConstBufferSequence const& buffers);
|
||||||
|
|
||||||
|
// Returns the number of bytes written successfully, sets the error code if a failure occurs
|
||||||
|
template <class ConstBufferSequence>
|
||||||
|
std::size_t write_some(ConstBufferSequence const& buffers, error_code& ec);
|
||||||
|
};
|
||||||
|
//]
|
||||||
|
template<class MutableBufferSequence>
|
||||||
|
std::size_t sync_read_stream::read_some(MutableBufferSequence const&)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
template<class MutableBufferSequence>
|
||||||
|
std::size_t sync_read_stream::read_some(MutableBufferSequence const&, error_code&)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t sync_write_stream::write_some(ConstBufferSequence const&)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t sync_write_stream::write_some(ConstBufferSequence const&, error_code&)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
BOOST_STATIC_ASSERT(is_sync_read_stream<sync_read_stream>::value);
|
||||||
|
BOOST_STATIC_ASSERT(is_sync_write_stream<sync_write_stream>::value);
|
||||||
|
|
||||||
|
//[code_core_1_refresher_4
|
||||||
|
template <class SyncWriteStream>
|
||||||
|
void hello (SyncWriteStream& stream)
|
||||||
|
{
|
||||||
|
net::const_buffer cb("Hello, world!", 13);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
auto bytes_transferred = stream.write_some(cb); // may throw
|
||||||
|
cb += bytes_transferred; // adjust the pointer and size
|
||||||
|
}
|
||||||
|
while (cb.size() > 0);
|
||||||
|
}
|
||||||
|
//]
|
||||||
|
|
||||||
|
//[code_core_1_refresher_5
|
||||||
|
template <class SyncWriteStream>
|
||||||
|
void hello (SyncWriteStream& stream, error_code& ec)
|
||||||
|
{
|
||||||
|
net::const_buffer cb("Hello, world!", 13);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
auto bytes_transferred = stream.write_some(cb, ec);
|
||||||
|
cb += bytes_transferred; // adjust the pointer and size
|
||||||
|
}
|
||||||
|
while (cb.size() > 0 && ! ec);
|
||||||
|
}
|
||||||
|
//]
|
||||||
|
|
||||||
|
//[code_core_1_refresher_6
|
||||||
|
// Intrusively specify an associated allocator and executor
|
||||||
|
struct handler
|
||||||
|
{
|
||||||
|
using allocator_type = std::allocator<char>;
|
||||||
|
allocator_type get_allocator() const noexcept;
|
||||||
|
|
||||||
|
using executor_type = net::io_context::executor_type;
|
||||||
|
executor_type get_executor() const noexcept;
|
||||||
|
|
||||||
|
void operator()(error_code, std::size_t);
|
||||||
|
};
|
||||||
|
//]
|
||||||
|
inline auto handler::get_allocator() const noexcept ->
|
||||||
|
allocator_type
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
inline auto handler::get_executor() const noexcept ->
|
||||||
|
executor_type
|
||||||
|
{
|
||||||
|
static net::io_context ioc;
|
||||||
|
return ioc.get_executor();
|
||||||
|
}
|
||||||
|
inline void handler::operator()(error_code, std::size_t)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//[code_core_1_refresher_7
|
||||||
|
template <class AsyncWriteStream, class WriteHandler>
|
||||||
|
void async_hello (AsyncWriteStream& stream, WriteHandler&& handler)
|
||||||
|
{
|
||||||
|
net::async_write (stream,
|
||||||
|
net::buffer("Hello, world!", 13),
|
||||||
|
std::forward<WriteHandler>(handler));
|
||||||
|
}
|
||||||
|
//]
|
||||||
|
|
||||||
|
//[code_core_1_refresher_8
|
||||||
|
template<
|
||||||
|
class AsyncWriteStream,
|
||||||
|
class ConstBufferSequence,
|
||||||
|
class WriteHandler>
|
||||||
|
auto
|
||||||
|
async_write(
|
||||||
|
AsyncWriteStream& stream,
|
||||||
|
ConstBufferSequence const& buffers,
|
||||||
|
WriteHandler&& handler) ->
|
||||||
|
typename net::async_result< // return-type customization point
|
||||||
|
typename std::decay<WriteHandler>::type, // type used to specialize async_result
|
||||||
|
void(error_code, std::size_t) // signature of the corresponding completion handler
|
||||||
|
>::return_type
|
||||||
|
{
|
||||||
|
net::async_completion<
|
||||||
|
WriteHandler, // completion handler customization point
|
||||||
|
void(error_code, std::size_t) // signature of the corresponding completion handler
|
||||||
|
> init(handler); // variable which holds the corresponding completion handler
|
||||||
|
|
||||||
|
(void)init.completion_handler; // the underlying completion handler used for the operation
|
||||||
|
|
||||||
|
// ...launch the operation (omitted for clarity)
|
||||||
|
|
||||||
|
return init.result.get();
|
||||||
|
}
|
||||||
|
//]
|
||||||
|
|
||||||
|
} // (anon)
|
||||||
|
|
||||||
|
struct core_1_refresher_test
|
||||||
|
: public beast::unit_test::suite
|
||||||
|
{
|
||||||
|
void
|
||||||
|
run() override
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(&snippets);
|
||||||
|
|
||||||
|
BEAST_EXPECT((static_cast<
|
||||||
|
std::string(*)(net::const_buffer const&)>(
|
||||||
|
&string_from_buffers<net::const_buffer>)));
|
||||||
|
|
||||||
|
BEAST_EXPECT(static_cast<
|
||||||
|
std::size_t(*)(net::ip::tcp::socket&, flat_buffer&)>(
|
||||||
|
&read_line<flat_buffer>));
|
||||||
|
|
||||||
|
BEAST_EXPECT(static_cast<
|
||||||
|
std::size_t(sync_read_stream::*)(
|
||||||
|
net::mutable_buffer const&)>(
|
||||||
|
&sync_read_stream::read_some));
|
||||||
|
BEAST_EXPECT(static_cast<
|
||||||
|
std::size_t(sync_read_stream::*)(
|
||||||
|
net::mutable_buffer const&, error_code&)>(
|
||||||
|
&sync_read_stream::read_some));
|
||||||
|
BEAST_EXPECT(static_cast<
|
||||||
|
std::size_t(sync_write_stream::*)(
|
||||||
|
net::const_buffer const&)>(
|
||||||
|
&sync_write_stream::write_some));
|
||||||
|
BEAST_EXPECT(static_cast<
|
||||||
|
std::size_t(sync_write_stream::*)(
|
||||||
|
net::const_buffer const&, error_code&)>(
|
||||||
|
&sync_write_stream::write_some));
|
||||||
|
|
||||||
|
BEAST_EXPECT(static_cast<
|
||||||
|
void(*)(test::stream&)>(
|
||||||
|
&hello<test::stream>));
|
||||||
|
|
||||||
|
BEAST_EXPECT(static_cast<
|
||||||
|
void(*)(test::stream&, error_code&)>(
|
||||||
|
&hello<test::stream>));
|
||||||
|
|
||||||
|
handler h;
|
||||||
|
h.get_allocator();
|
||||||
|
h.get_executor();
|
||||||
|
|
||||||
|
BEAST_EXPECT((&async_hello<test::stream, handler>));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(beast,doc,core_1_refresher);
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
} // boost
|
@@ -22,10 +22,8 @@
|
|||||||
namespace boost {
|
namespace boost {
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void
|
void
|
||||||
snippets()
|
core_3_layers_snippets()
|
||||||
{
|
{
|
||||||
#include "snippets.ipp"
|
#include "snippets.ipp"
|
||||||
{
|
{
|
||||||
@@ -231,8 +229,6 @@ BOOST_STATIC_ASSERT(is_sync_write_stream<counted_stream<test::stream>>::value);
|
|||||||
BOOST_STATIC_ASSERT(is_async_read_stream<counted_stream<test::stream>>::value);
|
BOOST_STATIC_ASSERT(is_async_read_stream<counted_stream<test::stream>>::value);
|
||||||
BOOST_STATIC_ASSERT(is_async_write_stream<counted_stream<test::stream>>::value);
|
BOOST_STATIC_ASSERT(is_async_write_stream<counted_stream<test::stream>>::value);
|
||||||
|
|
||||||
} // (anon)
|
|
||||||
|
|
||||||
struct core_3_layers_test
|
struct core_3_layers_test
|
||||||
: public beast::unit_test::suite
|
: public beast::unit_test::suite
|
||||||
{
|
{
|
||||||
@@ -246,7 +242,7 @@ struct core_3_layers_test
|
|||||||
void
|
void
|
||||||
run() override
|
run() override
|
||||||
{
|
{
|
||||||
BEAST_EXPECT(&snippets);
|
BEAST_EXPECT(&core_3_layers_snippets);
|
||||||
BEAST_EXPECT(&set_non_blocking<net::ip::tcp::socket>);
|
BEAST_EXPECT(&set_non_blocking<net::ip::tcp::socket>);
|
||||||
|
|
||||||
BEAST_EXPECT(&counted_stream<test::stream>::get_executor);
|
BEAST_EXPECT(&counted_stream<test::stream>::get_executor);
|
||||||
|
Reference in New Issue
Block a user