forked from boostorg/beast
WebSocket ping, fixes, coverage:
* Improve test coverage * tests for invokable in composed ops * Update documentation * Add License badge to README * Target Windows 7 SDK and later * Make role_type private * Remove extra unused masking functions * Allow stream reuse / reconnect after failure * Restructure logic of composed operations * Allow 0 for read_message_max meaning no limit * Respect keep alive when building HTTP responses * Check version in upgrade request * Response with 426 status on unsupported WebSocket version * Remove unnecessary Sec-WebSocket-Key in HTTP responses * Rename to mask_buffer_size * Remove maybe_throw * Add ping, async_ping, async_on_pong * Add ping_op * Add pong_op * Fix crash in accept_op * Fix suspend in close_op * Fix read_frame_op logic * Fix crash in read_op * Fix races in echo sync and async echo servers
This commit is contained in:
1 parent
a570b74038
commit
eb7bd6a2f1
40 files changed
+2757
-1365
No files matched your search
@@ -22,7 +22,6 @@
|
||||
[template mdash[] '''— ''']
|
||||
[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']
|
||||
[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']
|
||||
[template ticket[number]'''<ulink url="https://svn.boost.org/trac/boost/ticket/'''[number]'''">'''#[number]'''</ulink>''']
|
||||
[def __POSIX__ /POSIX/]
|
||||
[def __Windows__ /Windows/]
|
||||
[def __accept__ [@http://www.opengroup.org/onlinepubs/000095399/functions/accept.html `accept()`]]
|
||||
|
||||
+6
-1
@@ -73,16 +73,20 @@
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__close_reason">close_reason</link></member>
|
||||
<member><link linkend="beast.ref.websocket__ping_data">ping_data</link></member>
|
||||
<member><link linkend="beast.ref.websocket__stream">stream</link></member>
|
||||
<member><link linkend="beast.ref.websocket__reason_string">reason_string</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__auto_fragment_size">auto_fragment_size</link></member>
|
||||
<member><link linkend="beast.ref.websocket__decorate">decorate</link></member>
|
||||
<member><link linkend="beast.ref.websocket__keep_alive">keep_alive</link></member>
|
||||
<member><link linkend="beast.ref.websocket__mask_buffer_size">mask_buffer_size</link></member>
|
||||
<member><link linkend="beast.ref.websocket__message_type">message_type</link></member>
|
||||
<member><link linkend="beast.ref.websocket__pong_callback">pong_callback</link></member>
|
||||
<member><link linkend="beast.ref.websocket__read_buffer_size">read_buffer_size</link></member>
|
||||
<member><link linkend="beast.ref.websocket__read_message_max">read_message_max</link></member>
|
||||
<member><link linkend="beast.ref.websocket__write_buffer_size">write_buffer_size</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
@@ -94,6 +98,7 @@
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__close_code">close_code</link></member>
|
||||
<member><link linkend="beast.ref.websocket__error">error</link></member>
|
||||
<member><link linkend="beast.ref.websocket__opcode">opcode</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
A `BufferSequence` is a type meeting either of the following requirements:
|
||||
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*`ConstBufferSequence`]]
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*`MutableBufferSequence`]]
|
||||
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*`ConstBufferSequence`]]
|
||||
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*`MutableBufferSequence`]]
|
||||
|
||||
[endsect]
|
||||
@@ -17,7 +17,7 @@ In this table:
|
||||
|
||||
* `a` denotes a value of type `X`.
|
||||
|
||||
* `b` is a value meeting the requirements of [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConvertibleToConstBuffer.html [*`ConvertibleToConstBuffer`]].
|
||||
* `b` is a value meeting the requirements of [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConvertibleToConstBuffer.html [*`ConvertibleToConstBuffer`]].
|
||||
|
||||
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@ In the table below:
|
||||
[
|
||||
[`X::const_buffers_type`]
|
||||
[`T`]
|
||||
[`T` meets the requirements for [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html `ConstBufferSequence`].]
|
||||
[`T` meets the requirements for [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html `ConstBufferSequence`].]
|
||||
]
|
||||
[
|
||||
[`X::mutable_buffers_type`]
|
||||
[`U`]
|
||||
[`U` meets the requirements for [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html `MutableBufferSequence`].]
|
||||
[`U` meets the requirements for [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html `MutableBufferSequence`].]
|
||||
]
|
||||
[
|
||||
[`a.commit(n)`]
|
||||
|
||||
@@ -14,21 +14,21 @@ asynchronous I/O. They are based on concepts from `boost::asio`.
|
||||
|
||||
A type modeling [*`Stream`] meets either or both of the following requirements:
|
||||
|
||||
* [link beast.types.streams.AsyncStream [*`AsyncStream`]]
|
||||
* [link beast.types.streams.SyncStream [*`SyncStream`]]
|
||||
* [*`AsyncStream`]
|
||||
* [*`SyncStream`]
|
||||
|
||||
[heading:AsyncStream AsyncStream]
|
||||
|
||||
A type modeling [*`AsyncStream`] meets the following requirements:
|
||||
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*`AsyncReadStream`]]
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*`AsyncWriteStream`]]
|
||||
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncReadStream.html [*`AsyncReadStream`]]
|
||||
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*`AsyncWriteStream`]]
|
||||
|
||||
[heading:SyncStream SyncStream]
|
||||
|
||||
A type modeling [*`SyncStream`] meets the following requirements:
|
||||
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*`SyncReadStream`]]
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*`SyncWriteStream`]]
|
||||
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncReadStream.html [*`SyncReadStream`]]
|
||||
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncWriteStream.html [*`SyncWriteStream`]]
|
||||
|
||||
[endsect]
|
||||
+123
-81
@@ -46,13 +46,15 @@ model, handler allocation, and handler invocation hooks. Calls to
|
||||
Beast.WebSocket asynchronous initiation functions allow callers the choice
|
||||
of using a completion handler, stackful or stackless coroutines, futures,
|
||||
or user defined customizations (for example, Boost.Fiber). The
|
||||
implementation uses handler invocation hooks (`asio_handler_invoke`),
|
||||
implementation uses handler invocation hooks
|
||||
([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]),
|
||||
providing execution guarantees on composed operations in a manner
|
||||
identical to Boost.Asio. The implementation also uses handler allocation
|
||||
hooks (`asio_handler_allocate`) when allocating memory internally for
|
||||
composed operations.
|
||||
identical to Boost.Asio. The implementation also uses handler allocation hooks
|
||||
([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`])
|
||||
when allocating memory internally for composed operations.
|
||||
|
||||
There is no need for inheritance or virtual members in `websocket::stream`.
|
||||
There is no need for inheritance or virtual members in a
|
||||
[link beast.ref.websocket__stream `beast::websocket::stream`].
|
||||
All operations are templated and transparent to the compiler, allowing for
|
||||
maximum inlining and optimization.
|
||||
|
||||
@@ -67,43 +69,47 @@ both Boost.Asio and the WebSocket protocol specification described in
|
||||
[section:creating Creating the socket]
|
||||
|
||||
The interface to Beast's WebSocket implementation is a single template
|
||||
class [link beast.ref.websocket__stream `websocket::stream`] which wraps a
|
||||
"next layer" object. The next layer object must meet the requirements of
|
||||
`SyncReadStream` and `SyncWriteStream` if synchronous operations are performed,
|
||||
`AsyncReadStream` and `AsyncWriteStream` is asynchronous operations are
|
||||
performed, or both. Arguments supplied during construction are passed to
|
||||
next layer's constructor. Here we declare two websockets which have ownership
|
||||
of the next layer:
|
||||
class [link beast.ref.websocket__stream `beast::websocket::stream`] which
|
||||
wraps a "next layer" object. The next layer object must meet the requirements
|
||||
of [link beast.types.streams.SyncStream [*`SyncReadStream`]] if synchronous
|
||||
operations are performed, or
|
||||
[link beast.types.streams.AsyncStream [*`AsyncStream`]] if asynchronous
|
||||
operations are performed, or both. Arguments supplied during construction are
|
||||
passed to next layer's constructor. Here we declare two websockets which have
|
||||
ownership of the next layer:
|
||||
```
|
||||
io_service ios;
|
||||
websocket::stream<ip::tcp::socket> ws(ios);
|
||||
boost::asio::io_service ios;
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
|
||||
ssl::context ctx(ssl::context::sslv23);
|
||||
websocket::stream<ssl::stream<ip::tcp::socket>> wss(ios, ctx);
|
||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
||||
beast::websocket::stream<
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> wss(ios, ctx);
|
||||
```
|
||||
|
||||
For servers that can handshake in multiple protocols, it may be desired
|
||||
to wrap an object that already exists. This socket can be moved in:
|
||||
```
|
||||
tcp::socket&& sock;
|
||||
boost::asio::ip::tcp::socket&& sock;
|
||||
...
|
||||
websocket::stream<ip::tcp::socket> ws(std::move(sock));
|
||||
beast::websocket::stream<
|
||||
boost::asio::ip::tcp::socket> ws(std::move(sock));
|
||||
```
|
||||
|
||||
Or, the wrapper can be constructed with a non-owning reference. In
|
||||
this case, the caller is responsible for managing the lifetime of the
|
||||
underlying socket being wrapped:
|
||||
```
|
||||
tcp::socket sock;
|
||||
boost::asio::ip::tcp::socket sock;
|
||||
...
|
||||
websocket::stream<ip::tcp::socket&> ws(sock);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
||||
```
|
||||
|
||||
The layer being wrapped can be accessed through the websocket's "next layer",
|
||||
permitting callers to interact directly with its interface.
|
||||
```
|
||||
ssl::context ctx(ssl::context::sslv23);
|
||||
websocket::stream<ssl::stream<ip::tcp::socket>> ws(ios, ctx);
|
||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
||||
beast::websocket::stream<
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> ws(ios, ctx);
|
||||
...
|
||||
ws.next_layer().shutdown(); // ssl::stream shutdown
|
||||
```
|
||||
@@ -122,17 +128,18 @@ Connections are established by using the interfaces which already exist
|
||||
for the next layer. For example, making an outgoing connection:
|
||||
```
|
||||
std::string const host = "mywebapp.com";
|
||||
io_service ios;
|
||||
tcp::resolver r(ios);
|
||||
websocket::stream<ip::tcp::socket> ws(ios);
|
||||
connect(ws.next_layer(), r.resolve(tcp::resolver::query{host, "ws"}));
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::ip::tcp::resolver r(ios);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
boost::asio::connect(ws.next_layer(),
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "ws"}));
|
||||
```
|
||||
|
||||
Accepting an incoming connection:
|
||||
```
|
||||
void do_accept(tcp::acceptor& acceptor)
|
||||
void do_accept(boost::asio::ip::tcp::acceptor& acceptor)
|
||||
{
|
||||
websocket::stream<ip::tcp::socket> ws(acceptor.get_io_service());
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(acceptor.get_io_service());
|
||||
acceptor.accept(ws.next_layer());
|
||||
}
|
||||
```
|
||||
@@ -149,26 +156,26 @@ A WebSocket session begins when one side sends the HTTP Upgrade request
|
||||
for websocket, and the other side sends an appropriate HTTP response
|
||||
indicating that the request was accepted and that the connection has
|
||||
been upgraded. The HTTP Upgrade request must include the Host HTTP field,
|
||||
and the URI of the resource to request. `hanshake` is used to send the
|
||||
and the URI of the resource to request. `handshake` is used to send the
|
||||
request with the required host and resource strings.
|
||||
```
|
||||
websocket::stream<ip::tcp::socket> ws(ios);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
...
|
||||
ws.set_option(websocket::keep_alive(true));
|
||||
ws.handshake("ws.mywebapp.com:80", "/cgi-bin/bitcoin-prices");
|
||||
ws.set_option(beast::websocket::keep_alive(true));
|
||||
ws.handshake("ws.example.com:80", "/cgi-bin/bitcoin-prices");
|
||||
```
|
||||
|
||||
The `websocket::stream` automatically handles receiving and processing
|
||||
the HTTP response to the handshake request. The call to handshake is
|
||||
successful if a HTTP response is received with the 101 "Switching Protocols"
|
||||
status code. On failure, an error is returned or an exception is thrown.
|
||||
Depending on the keep alive setting, the socket may remain open for a
|
||||
subsequent handshake attempt
|
||||
The [link beast.ref.websocket__stream `beast::websocket::stream`] automatically
|
||||
handles receiving and processing the HTTP response to the handshake request.
|
||||
The call to handshake is successful if a HTTP response is received with the
|
||||
101 "Switching Protocols" status code. On failure, an error is returned or an
|
||||
exception is thrown. Depending on the keep alive setting, the socket may remain
|
||||
open for a subsequent handshake attempt
|
||||
|
||||
Performing a handshake for an incoming websocket upgrade request operates
|
||||
similarly. If the handshake fails, an error is returned or exception thrown:
|
||||
```
|
||||
websocket::stream<ip::tcp::socket> ws(ios);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
...
|
||||
ws.accept();
|
||||
```
|
||||
@@ -178,12 +185,12 @@ on the connection, or might have already received an entire HTTP request
|
||||
containing the upgrade request. Overloads of `accept` allow callers to
|
||||
pass in this additional buffered handshake data.
|
||||
```
|
||||
void do_accept(tcp::socket& sock)
|
||||
void do_accept(boost::asio::ip::tcp::socket& sock)
|
||||
{
|
||||
boost::asio::streambuf sb;
|
||||
read_until(sock, sb, "\r\n\r\n");
|
||||
boost::asio::read_until(sock, sb, "\r\n\r\n");
|
||||
...
|
||||
websocket::stream<ip::tcp::socket&> ws(sock);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
||||
ws.accept(sb.data());
|
||||
...
|
||||
}
|
||||
@@ -192,12 +199,12 @@ void do_accept(tcp::socket& sock)
|
||||
Alternatively, the caller can pass an entire HTTP request if it was
|
||||
obtained elsewhere:
|
||||
```
|
||||
void do_accept(tcp::socket& sock)
|
||||
void do_accept(boost::asio::ip::tcp::socket& sock)
|
||||
{
|
||||
boost::asio::streambuf sb;
|
||||
http::request<http::empty_body> request;
|
||||
http::read(sock, request);
|
||||
if(http::is_upgrade(request))
|
||||
beast::http::request<http::empty_body> request;
|
||||
beast::http::read(sock, request);
|
||||
if(beast::http::is_upgrade(request))
|
||||
{
|
||||
websocket::stream<ip::tcp::socket&> ws(sock);
|
||||
ws.accept(request);
|
||||
@@ -206,8 +213,6 @@ void do_accept(tcp::socket& sock)
|
||||
}
|
||||
```
|
||||
|
||||
[note Identifiers in the `http` namespace are part of Beast.HTTP. ]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -218,20 +223,21 @@ After the WebSocket handshake is accomplished, callers may send and receive
|
||||
messages using the message oriented interface. This interface requires that
|
||||
all of the buffers representing the message are known ahead of time:
|
||||
```
|
||||
void echo(websocket::stream<ip::tcp::socket>& ws)
|
||||
void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
||||
{
|
||||
streambuf sb;
|
||||
websocket::opcode::value op;
|
||||
beast::streambuf sb;
|
||||
beast::websocket::opcode::value op;
|
||||
ws.read(sb);
|
||||
|
||||
ws.set_option(websocket::message_type(op));
|
||||
websocket::write(ws, sb.data());
|
||||
ws.set_option(beast::websocket::message_type(op));
|
||||
ws.write(sb.data());
|
||||
sb.consume(sb.size());
|
||||
}
|
||||
```
|
||||
|
||||
[important Calls to `set_option` must be made from the same implicit
|
||||
or explicit strand as that used to perform other operations. ]
|
||||
[important Calls to [link beast.ref.websocket__stream.set_option `set_option`]
|
||||
must be made from the same implicit or explicit strand as that used to perform
|
||||
other operations. ]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -249,18 +255,19 @@ message ahead of time:
|
||||
For these cases, the frame oriented interface may be used. This
|
||||
example reads and echoes a complete message using this interface:
|
||||
```
|
||||
void echo(websocket::stream<ip::tcp::socket>& ws)
|
||||
void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
||||
{
|
||||
streambuf sb;
|
||||
websocket::frame_info fi;
|
||||
beast::streambuf sb;
|
||||
beast::websocket::frame_info fi;
|
||||
for(;;)
|
||||
{
|
||||
ws.read_frame(fi, sb);
|
||||
if(fi.fin)
|
||||
break;
|
||||
}
|
||||
ws.set_option(websocket::message_type(fi.op));
|
||||
consuming_buffers<streambuf::const_buffers_type> cb(sb.data());
|
||||
ws.set_option(beast::websocket::message_type(fi.op));
|
||||
beast::consuming_buffers<
|
||||
beast::streambuf::const_buffers_type> cb(sb.data());
|
||||
for(;;)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
@@ -287,10 +294,11 @@ void echo(websocket::stream<ip::tcp::socket>& ws)
|
||||
|
||||
During read operations, the implementation automatically reads and processes
|
||||
WebSocket control frames such as ping, pong, and close. Pings are replied
|
||||
to as soon as possible, pongs are noted. The receipt of a close frame
|
||||
initiates the WebSocket close procedure, eventually resulting in the
|
||||
error code `websocket::error::closed` being delivered to the caller in
|
||||
a subsequent read operation, assuming no other error takes place.
|
||||
to as soon as possible, pongs are delivered to the pong callback. The receipt
|
||||
of a close frame initiates the WebSocket close procedure, eventually resulting
|
||||
in the error code [link beast.ref.websocket__error `error::closed`] being
|
||||
delivered to the caller in a subsequent read operation, assuming no other error
|
||||
takes place.
|
||||
|
||||
To ensure timely delivery of control frames, large messages are broken up
|
||||
into smaller sized frames. The implementation chooses the size and number
|
||||
@@ -298,19 +306,49 @@ of the frames making up the message. The automatic fragment size option
|
||||
gives callers control over the size of these frames:
|
||||
```
|
||||
...
|
||||
ws.set_option(websocket::auto_fragment_size(8192));
|
||||
ws.set_option(beast::websocket::auto_fragment_size(8192));
|
||||
```
|
||||
|
||||
The WebSocket protocol defines a procedure and control message for initiating
|
||||
a close of the session. Handling of close initiated by the remote end of the
|
||||
connection is performed automatically. To manually initiate a close, use
|
||||
`websocket::stream::close`:
|
||||
[link beast.ref.websocket__stream.close `close`]:
|
||||
```
|
||||
ws.close();
|
||||
```
|
||||
|
||||
[note To receive the `websocket::error::closed` error, a read operation
|
||||
is required. ]
|
||||
[note To receive the [link beast.ref.websocket__error `error::closed`]
|
||||
error, a read operation is required. ]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:pongs Pong messages]
|
||||
|
||||
To receive pong control frames, callers may register a "pong callback" using
|
||||
[link beast.ref.websocket__stream.set_option `set_option`]:
|
||||
|
||||
the following signature:
|
||||
```
|
||||
void on_pong(ping_data const& payload);
|
||||
...
|
||||
ws.set_option(pong_callback{&on_pong});
|
||||
```
|
||||
|
||||
When a pong callback is registered, any pongs received through either
|
||||
synchronous read functions or asynchronous read functions will invoke the
|
||||
pong callback, passing the payload in the pong message as the argument.
|
||||
|
||||
Unlike regular completion handlers used in calls to asynchronous initiation
|
||||
functions, the pong callback only needs to be set once. The callback is not
|
||||
reset when a pong is received. The same callback is used for both synchronous
|
||||
and asynchronous reads. The pong callback is passive; in order to receive
|
||||
pongs, a synchronous or asynchronous stream read function must be active.
|
||||
|
||||
[note When an asynchronous read function receives a pong, the the pong callback
|
||||
is invoked in the same manner as that used to invoke the final completion
|
||||
handler of the corresponding read function.]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -320,7 +358,8 @@ is required. ]
|
||||
|
||||
Because calls to read data may return a variable amount of bytes, the
|
||||
interface to calls that read data require an object that meets the requirements
|
||||
of `Streambuf`. This concept is modeled on `boost::asio::basic_streambuf`.
|
||||
of [link beast.types.Streambuf [*`Streambuf`]]. This concept is modeled on
|
||||
[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
|
||||
|
||||
The implementation does not perform queueing or buffering of messages. If
|
||||
desired, these features should be provided by callers. The impact of this
|
||||
@@ -331,6 +370,7 @@ of the underlying TCP/IP connection.
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:async Asynchronous interface]
|
||||
|
||||
Asynchronous versions are available for all functions:
|
||||
@@ -361,12 +401,14 @@ void echo(websocket::stream<ip::tcp::socket>& ws,
|
||||
|
||||
|
||||
|
||||
[section:io_service io_service]
|
||||
[section:io_service The io_service]
|
||||
|
||||
The creation and operation of the `boost::asio::io_service` associated with
|
||||
the underlying stream is left to the callers, permitting any implementation
|
||||
strategy including one that does not require threads for environments where
|
||||
threads are unavailable. Beast.WSProto itself does not use or require threads.
|
||||
The creation and operation of the
|
||||
[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/io_service.html `boost::asio::io_service`]
|
||||
associated with the underlying stream is left to the callers, permitting any
|
||||
implementation strategy including one that does not require threads for
|
||||
environments where threads are unavailable. Beast.WebSocket itself does not
|
||||
use or require threads.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -374,13 +416,13 @@ threads are unavailable. Beast.WSProto itself does not use or require threads.
|
||||
|
||||
[section:safety Thread Safety]
|
||||
|
||||
Like a regular asio socket, a `websocket::stream` is not thread safe. Callers
|
||||
are responsible for synchronizing operations on the socket using an implicit
|
||||
or explicit strand, as per the Asio documentation. The asynchronous interface
|
||||
supports one active read and one active write simultaneously. Undefined
|
||||
behavior results if two or more reads or two or more writes are attempted
|
||||
concurrently. Caller initiated WebSocket ping, pong, and close operations
|
||||
each count as an active write.
|
||||
Like a regular asio socket, a [link beast.ref.websocket__stream `stream`] is
|
||||
not thread safe. Callers are responsible for synchronizing operations on the
|
||||
socket using an implicit or explicit strand, as per the Asio documentation.
|
||||
The asynchronous interface supports one active read and one active write
|
||||
simultaneously. Undefined behavior results if two or more reads or two or
|
||||
more writes are attempted concurrently. Caller initiated WebSocket ping, pong,
|
||||
and close operations each count as an active write.
|
||||
|
||||
The implementation uses composed asynchronous operations internally; a high
|
||||
level read can cause both reads and writes to take place on the underlying
|
||||
|
||||
Reference in new issue
Block a user