Loading…
|
Translation changed |
|
|
String added in the repository |
variablelist
[[1. Synchronous Interface][ Beast offers full support for WebSockets using a synchronous interface. It uses the same style of interfaces found in Boost.Asio: versions that throw exceptions, or versions that return the error code in a reference parameter: [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [websocketpp] ][ [``` template<class DynamicBuffer> void read(DynamicBuffer& dynabuf) ```] [ /<not available>/ ] ]]]] [[2. Connection Model][ websocketpp supports multiple transports by utilizing a trait, the `config::transport_type` ([@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/connection.hpp#L60 asio transport example]) To get an idea of the complexity involved with implementing a transport, compare the asio transport to the [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 `iostream` transport] (a layer that allows websocket communication over a `std::iostream`). In contrast, Beast abstracts the transport by defining just one [*`NextLayer`] template argument The type requirements for [*`NextLayer`] are already familiar to users as they are documented in Asio: __AsyncReadStream__, __AsyncWriteStream__, __SyncReadStream__, __SyncWriteStream__. The type requirements for instantiating `beast::websocket::stream` versus `websocketpp::connection` with user defined types are vastly reduced (18 functions versus 2). Note that websocketpp connections are passed by `shared_ptr`. Beast does not use `shared_ptr` anywhere in its public interface. A `beast::websocket::stream` is constructible and movable in a manner identical to a `boost::asio::ip::tcp::socket`. Callers can put such objects in a `shared_ptr` if they want to, but there is no requirement to do so. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L234 websocketpp]] ][ [``` template<class NextLayer> class stream { NextLayer next_layer_; ... } ```] [``` template <typename config> class connection : public config::transport_type::transport_con_type , public config::connection_base { public: typedef lib::shared_ptr<type> ptr; ... } ```] ]]]] [[3. Client and Server Role][ websocketpp provides multi-role support through a hierarchy of different classes. A `beast::websocket::stream` is role-agnostic, it offers member functions to perform both client and server handshakes in the same class. The same types are used for client and server streams. [table [ [Beast] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/server_endpoint.hpp#L39 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/client_endpoint.hpp#L42 also]] ][ [ /<not needed>/ ] [``` template <typename config> class client : public endpoint<connection<config>,config>; template <typename config> class server : public endpoint<connection<config>,config>; ```] ]]]] [[4. Thread Safety][ websocketpp uses mutexes to protect shared data from concurrent access. In contrast, Beast does not use mutexes anywhere in its implementation. Instead, it follows the Asio pattern. Calls to asynchronous initiation functions use the same method to invoke intermediate handlers as the method used to invoke the final handler, through the associated executor mechanism. The only requirement in Beast is that calls to asynchronous initiation functions are made from the same implicit or explicit strand. For example, if the `io_context` associated with a `beast::websocket::stream` is single threaded, this counts as an implicit strand and no performance costs associated with mutexes are incurred. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/read_frame_op.ipp#L118 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L706 websocketpp]] ][ [``` mutex_type m_read_mutex; ```] ]]]] [[5. Callback Model][ websocketpp requires a one-time call to set the handler for each event in its interface (for example, upon message receipt). The handler is represented by a `std::function` equivalent. Its important to recognize that the websocketpp interface performs type-erasure on this handler. In comparison, Beast handlers are specified in a manner identical to Boost.Asio. They are function objects which can be copied or moved but most importantly they are not type erased. The compiler can see through the type directly to the implementation, permitting optimization. Furthermore, Beast follows the Asio rules for treatment of handlers. It respects any allocation, executors, cancellations associated with the handler through the use of argument dependent lookup overloads of functions such as `bind_allocaotr`. The Beast completion handler is provided at the call site. For each call to an asynchronous initiation function, it is guaranteed that there will be exactly one final call to the handler. This functions exactly the same way as the asynchronous initiation functions found in Boost.Asio, allowing the composition of higher level abstractions. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L834 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L281 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L473 also]] ][ [``` template< class DynamicBuffer, // Supports user defined types class ReadHandler // Handler is NOT type-erased > typename async_completion< // Return value customization ReadHandler, // supports futures and coroutines void(error_code) >::result_type async_read( DynamicBuffer& dynabuf, ReadHandler&& handler); ```] [``` typedef lib::function< void(connection_hdl,message_ptr) > message_handler; void set_message_handler(message_handler h); ```] ]]]] [[6. Extensible Asynchronous Model][ Beast fully supports the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf Extensible Asynchronous Model] developed by Christopher Kohlhoff, author of Boost.Asio (see Section 8). Beast websocket asynchronous interfaces may be used seamlessly with `std::future` stackful/stackless coroutines, or user defined customizations. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/stream.ipp#L378 Beast]] [websocketpp] ][ [``` beast::async_completion< ReadHandler, void(error_code)> completion{handler}; read_op< DynamicBuffer, decltype(completion.handler)>{ completion.handler, *this, op, buffer}; return completion.result.get(); // Customization point ```] [ /<not available>/ ] ]]]] [[7. Message Buffering][ websocketpp defines a message buffer, passed in arguments by `shared_ptr`, and an associated message manager which permits aggregation and reuse of memory. The implementation of `websocketpp::message` uses a `std::string` to hold the payload. If an incoming message is broken up into multiple frames, the string may be reallocated for each continuation frame. The `std::string` always uses the standard allocator, it is not possible to customize the choice of allocator. Beast allows callers to specify the object for receiving the message or frame data, which is of any type meeting the requirements of __DynamicBuffer__ (modeled after `boost::asio::streambuf`). Beast comes with the class __basic_multi_buffer__, an efficient implementation of the __DynamicBuffer__ concept which makes use of multiple allocated octet arrays. If an incoming message is broken up into multiple pieces, no reallocation occurs. Instead, new allocations are appended to the sequence when existing allocations are filled. Beast does not impose any particular memory management model on callers. The __basic_multi_buffer__ provided by beast supports standard allocators through a template argument. Use the __DynamicBuffer__ that comes with beast, customize the allocator if you desire, or provide your own type that meets the requirements. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/message_buffer/message.hpp#L78 websocketpp]] ][ [``` template<class DynamicBuffer> read(DynamicBuffer& dynabuf); ```] [``` template <template<class> class con_msg_manager> class message { public: typedef lib::shared_ptr<message> ptr; ... std::string m_payload; ... }; ```] ]]]] [[8. Sending Messages][ When sending a message, websocketpp requires that the payload is packaged in a `websocketpp::message` object using `std::string` as the storage, or it requires a copy of the caller provided buffer by constructing a new message object. Messages are placed onto an outgoing queue. An asynchronous write operation runs in the background to clear the queue. No user facing handler can be registered to be notified when messages or frames have completed sending. Beast doesn't allocate or make copies of buffers when sending data. The caller's buffers are sent in-place. You can use any object meeting the requirements of __ConstBufferSequence, permitting efficient scatter-gather I/O. The [*ConstBufferSequence] interface allows callers to send data from memory-mapped regions (not possible in websocketpp). Callers can also use the same buffers to send data to multiple streams, for example broadcasting common subscription data to many clients at once. For each call to `async_write` the completion handler is called once when the data finishes sending, in a manner identical to `boost::asio::async_write`. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1048 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L672 websocketpp]] ][ [``` template<class ConstBufferSequence> void write(ConstBufferSequence const& buffers); ```] [``` lib::error_code send(std::string const & payload, frame::opcode::value op = frame::opcode::text); ... lib::error_code send(message_ptr msg); ```] ]]]] [[9. Streaming Messages][ websocketpp requires that the entire message fit into memory, and that the size is known ahead of time. Beast allows callers to compose messages in individual frames. This is useful when the size of the data is not known ahead of time or if it is not desired to buffer the entire message in memory at once before sending it. For example, sending periodic output of a database query running on a coroutine. Or sending the contents of a file in pieces, without bringing it all into memory. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1151 Beast]] [websocketpp] ][ [``` template<class ConstBufferSequence> void write_some(bool fin, ConstBufferSequence const& buffers); ```] [ /<not available>/ ] ]]]] [[10. Flow Control][ The websocketpp read implementation continuously reads asynchronously from the network and buffers message data. To prevent unbounded growth and leverage TCP/IP's flow control mechanism, callers can periodically turn this 'read pump' off and back on. In contrast a `beast::websocket::stream` does not independently begin background activity, nor does it buffer messages. It receives data only when there is a call to an asynchronous initiation function (for example `beast::websocket::stream::async_read`) with an associated handler. Applications do not need to implement explicit logic to regulate the flow of data. Instead, they follow the traditional model of issuing a read, receiving a read completion, processing the message, then issuing a new read and repeating the process. [table [ [Beast] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L728 websocketpp]] ][ [ /<implicit>/ ] [``` lib::error_code pause_reading(); lib::error_code resume_reading(); ```] ]]]] [[11. Connection Establishment][ websocketpp offers the `endpoint` class which can handle binding and listening to a port, and spawning connection objects. Beast does not reinvent the wheel here, callers use the interfaces already in `boost::asio` for receiving incoming connections resolving host names, or establishing outgoing connections. After the socket (or `boost::asio::ssl::stream`) is connected, the `beast::websocket::stream` is constructed around it and the WebSocket handshake can be performed. Beast users are free to implement their own "connection manager", but there is no requirement to do so. [table [ [[@http://www.boost.org/doc/html/boost_asio/reference/async_connect.html Beast], [@http://www.boost.org/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html also]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/endpoint.hpp#L52 websocketpp]] ][ [``` #include <boost/asio.hpp> ```] [``` template <typename config> class endpoint : public config::socket_type; ```] ]]]] [[12. WebSocket Handshaking][ Callers invoke `beast::websocket::accept` to perform the WebSocket handshake, but there is no requirement to use this function. Advanced users can perform the WebSocket handshake themselves. Beast WebSocket provides the tools for composing the request or response, and the Beast HTTP interface provides the container and algorithms for sending and receiving HTTP/1 messages including the necessary HTTP Upgrade request for establishing the WebSocket session. Beast allows the caller to pass the incoming HTTP Upgrade request for the cases where the caller has already received an HTTP message. This flexibility permits novel and robust implementations. For example, a listening socket that can handshake in multiple protocols on the same port. Sometimes callers want to read some bytes on the socket before reading the WebSocket HTTP Upgrade request. Beast allows these already-received bytes to be supplied to an overload of the accepting function to permit sophisticated features. For example, a listening socket that can accept both regular WebSocket and Secure WebSocket (SSL) connections. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L501 Beast], [@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L401 also]] [websocketpp] ][ [``` template<class ConstBufferSequence> void accept(ConstBufferSequence const& buffers); template<class Allocator> void accept(http::header<true, http::basic_fields<Allocator>> const& req); ```] [ /<not available>/ ] ]]]]
variablelist
[[1. Synchronous Interface][ Beast offers full support for WebSockets using a synchronous interface. It uses the same style of interfaces found in Boost.Asio: versions that throw exceptions, or versions that return the error code in a reference parameter: [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [websocketpp] ][ [``` template<class DynamicBuffer> void read(DynamicBuffer& dynabuf) ```] [ /<not available>/ ] ]]]] [[2. Connection Model][ websocketpp supports multiple transports by utilizing a trait, the `config::transport_type` ([@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/connection.hpp#L60 asio transport example]) To get an idea of the complexity involved with implementing a transport, compare the asio transport to the [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 `iostream` transport] (a layer that allows websocket communication over a `std::iostream`). In contrast, Beast abstracts the transport by defining just one [*`NextLayer`] template argument The type requirements for [*`NextLayer`] are already familiar to users as they are documented in Asio: __AsyncReadStream__, __AsyncWriteStream__, __SyncReadStream__, __SyncWriteStream__. The type requirements for instantiating `beast::websocket::stream` versus `websocketpp::connection` with user defined types are vastly reduced (18 functions versus 2). Note that websocketpp connections are passed by `shared_ptr`. Beast does not use `shared_ptr` anywhere in its public interface. A `beast::websocket::stream` is constructible and movable in a manner identical to a `boost::asio::ip::tcp::socket`. Callers can put such objects in a `shared_ptr` if they want to, but there is no requirement to do so. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L234 websocketpp]] ][ [``` template<class NextLayer> class stream { NextLayer next_layer_; ... } ```] [``` template <typename config> class connection : public config::transport_type::transport_con_type , public config::connection_base { public: typedef lib::shared_ptr<type> ptr; ... } ```] ]]]] [[3. Client and Server Role][ websocketpp provides multi-role support through a hierarchy of different classes. A `beast::websocket::stream` is role-agnostic, it offers member functions to perform both client and server handshakes in the same class. The same types are used for client and server streams. [table [ [Beast] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/server_endpoint.hpp#L39 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/client_endpoint.hpp#L42 also]] ][ [ /<not needed>/ ] [``` template <typename config> class client : public endpoint<connection<config>,config>; template <typename config> class server : public endpoint<connection<config>,config>; ```] ]]]] [[4. Thread Safety][ websocketpp uses mutexes to protect shared data from concurrent access. In contrast, Beast does not use mutexes anywhere in its implementation. Instead, it follows the Asio pattern. Calls to asynchronous initiation functions use the same method to invoke intermediate handlers as the method used to invoke the final handler, through the associated executor mechanism. The only requirement in Beast is that calls to asynchronous initiation functions are made from the same implicit or explicit strand. For example, if the `io_context` associated with a `beast::websocket::stream` is single threaded, this counts as an implicit strand and no performance costs associated with mutexes are incurred. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/read_frame_op.ipp#L118 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L706 websocketpp]] ][ [``` mutex_type m_read_mutex; ```] ]]]] [[5. Callback Model][ websocketpp requires a one-time call to set the handler for each event in its interface (for example, upon message receipt). The handler is represented by a `std::function` equivalent. Its important to recognize that the websocketpp interface performs type-erasure on this handler. In comparison, Beast handlers are specified in a manner identical to Boost.Asio. They are function objects which can be copied or moved but most importantly they are not type erased. The compiler can see through the type directly to the implementation, permitting optimization. Furthermore, Beast follows the Asio rules for treatment of handlers. It respects any allocation, executors, cancellations associated with the handler through the use of argument dependent lookup overloads of functions such as `bind_allocaotr`. The Beast completion handler is provided at the call site. For each call to an asynchronous initiation function, it is guaranteed that there will be exactly one final call to the handler. This functions exactly the same way as the asynchronous initiation functions found in Boost.Asio, allowing the composition of higher level abstractions. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L834 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L281 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L473 also]] ][ [``` template< class DynamicBuffer, // Supports user defined types class ReadHandler // Handler is NOT type-erased > typename async_completion< // Return value customization ReadHandler, // supports futures and coroutines void(error_code) >::result_type async_read( DynamicBuffer& dynabuf, ReadHandler&& handler); ```] [``` typedef lib::function< void(connection_hdl,message_ptr) > message_handler; void set_message_handler(message_handler h); ```] ]]]] [[6. Extensible Asynchronous Model][ Beast fully supports the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf Extensible Asynchronous Model] developed by Christopher Kohlhoff, author of Boost.Asio (see Section 8). Beast websocket asynchronous interfaces may be used seamlessly with `std::future` stackful/stackless coroutines, or user defined customizations. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/stream.ipp#L378 Beast]] [websocketpp] ][ [``` beast::async_completion< ReadHandler, void(error_code)> completion{handler}; read_op< DynamicBuffer, decltype(completion.handler)>{ completion.handler, *this, op, buffer}; return completion.result.get(); // Customization point ```] [ /<not available>/ ] ]]]] [[7. Message Buffering][ websocketpp defines a message buffer, passed in arguments by `shared_ptr`, and an associated message manager which permits aggregation and reuse of memory. The implementation of `websocketpp::message` uses a `std::string` to hold the payload. If an incoming message is broken up into multiple frames, the string may be reallocated for each continuation frame. The `std::string` always uses the standard allocator, it is not possible to customize the choice of allocator. Beast allows callers to specify the object for receiving the message or frame data, which is of any type meeting the requirements of __DynamicBuffer__ (modeled after `boost::asio::streambuf`). Beast comes with the class __basic_multi_buffer__, an efficient implementation of the __DynamicBuffer__ concept which makes use of multiple allocated octet arrays. If an incoming message is broken up into multiple pieces, no reallocation occurs. Instead, new allocations are appended to the sequence when existing allocations are filled. Beast does not impose any particular memory management model on callers. The __basic_multi_buffer__ provided by beast supports standard allocators through a template argument. Use the __DynamicBuffer__ that comes with beast, customize the allocator if you desire, or provide your own type that meets the requirements. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/message_buffer/message.hpp#L78 websocketpp]] ][ [``` template<class DynamicBuffer> read(DynamicBuffer& dynabuf); ```] [``` template <template<class> class con_msg_manager> class message { public: typedef lib::shared_ptr<message> ptr; ... std::string m_payload; ... }; ```] ]]]] [[8. Sending Messages][ When sending a message, websocketpp requires that the payload is packaged in a `websocketpp::message` object using `std::string` as the storage, or it requires a copy of the caller provided buffer by constructing a new message object. Messages are placed onto an outgoing queue. An asynchronous write operation runs in the background to clear the queue. No user facing handler can be registered to be notified when messages or frames have completed sending. Beast doesn't allocate or make copies of buffers when sending data. The caller's buffers are sent in-place. You can use any object meeting the requirements of __ConstBufferSequence, permitting efficient scatter-gather I/O. The [*ConstBufferSequence] interface allows callers to send data from memory-mapped regions (not possible in websocketpp). Callers can also use the same buffers to send data to multiple streams, for example broadcasting common subscription data to many clients at once. For each call to `async_write` the completion handler is called once when the data finishes sending, in a manner identical to `boost::asio::async_write`. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1048 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L672 websocketpp]] ][ [``` template<class ConstBufferSequence> void write(ConstBufferSequence const& buffers); ```] [``` lib::error_code send(std::string const & payload, frame::opcode::value op = frame::opcode::text); ... lib::error_code send(message_ptr msg); ```] ]]]] [[9. Streaming Messages][ websocketpp requires that the entire message fit into memory, and that the size is known ahead of time. Beast allows callers to compose messages in individual frames. This is useful when the size of the data is not known ahead of time or if it is not desired to buffer the entire message in memory at once before sending it. For example, sending periodic output of a database query running on a coroutine. Or sending the contents of a file in pieces, without bringing it all into memory. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1151 Beast]] [websocketpp] ][ [``` template<class ConstBufferSequence> void write_some(bool fin, ConstBufferSequence const& buffers); ```] [ /<not available>/ ] ]]]] [[10. Flow Control][ The websocketpp read implementation continuously reads asynchronously from the network and buffers message data. To prevent unbounded growth and leverage TCP/IP's flow control mechanism, callers can periodically turn this 'read pump' off and back on. In contrast a `beast::websocket::stream` does not independently begin background activity, nor does it buffer messages. It receives data only when there is a call to an asynchronous initiation function (for example `beast::websocket::stream::async_read`) with an associated handler. Applications do not need to implement explicit logic to regulate the flow of data. Instead, they follow the traditional model of issuing a read, receiving a read completion, processing the message, then issuing a new read and repeating the process. [table [ [Beast] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L728 websocketpp]] ][ [ /<implicit>/ ] [``` lib::error_code pause_reading(); lib::error_code resume_reading(); ```] ]]]] [[11. Connection Establishment][ websocketpp offers the `endpoint` class which can handle binding and listening to a port, and spawning connection objects. Beast does not reinvent the wheel here, callers use the interfaces already in `boost::asio` for receiving incoming connections resolving host names, or establishing outgoing connections. After the socket (or `boost::asio::ssl::stream`) is connected, the `beast::websocket::stream` is constructed around it and the WebSocket handshake can be performed. Beast users are free to implement their own "connection manager", but there is no requirement to do so. [table [ [[@http://www.boost.org/doc/html/boost_asio/reference/async_connect.html Beast], [@http://www.boost.org/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html also]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/endpoint.hpp#L52 websocketpp]] ][ [``` #include <boost/asio.hpp> ```] [``` template <typename config> class endpoint : public config::socket_type; ```] ]]]] [[12. WebSocket Handshaking][ Callers invoke `beast::websocket::accept` to perform the WebSocket handshake, but there is no requirement to use this function. Advanced users can perform the WebSocket handshake themselves. Beast WebSocket provides the tools for composing the request or response, and the Beast HTTP interface provides the container and algorithms for sending and receiving HTTP/1 messages including the necessary HTTP Upgrade request for establishing the WebSocket session. Beast allows the caller to pass the incoming HTTP Upgrade request for the cases where the caller has already received an HTTP message. This flexibility permits novel and robust implementations. For example, a listening socket that can handshake in multiple protocols on the same port. Sometimes callers want to read some bytes on the socket before reading the WebSocket HTTP Upgrade request. Beast allows these already-received bytes to be supplied to an overload of the accepting function to permit sophisticated features. For example, a listening socket that can accept both regular WebSocket and Secure WebSocket (SSL) connections. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L501 Beast], [@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L401 also]] [websocketpp] ][ [``` template<class ConstBufferSequence> void accept(ConstBufferSequence const& buffers); template<class Allocator> void accept(http::header<true, http::basic_fields<Allocator>> const& req); ```] [ /<not available>/ ] ]]]] |
[[1. Synchronous Interface][
Beast offers full support for WebSockets using a synchronous interface. It uses the same style of interfaces found in Boost.Asio: versions that throw exceptions, or versions that return the error code in a reference parameter:
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [websocketpp] ][ [``` template<class DynamicBuffer> void read(DynamicBuffer& dynabuf) ```] [ /<not available>/ ] ]]]]
[[2. Connection Model][
websocketpp supports multiple transports by utilizing a trait, the `config::transport_type` ([@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/connection.hpp#L60 asio transport example]) To get an idea of the complexity involved with implementing a transport, compare the asio transport to the [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 `iostream` transport] (a layer that allows websocket communication over a `std::iostream`).
In contrast, Beast abstracts the transport by defining just one [*`NextLayer`] template argument The type requirements for [*`NextLayer`] are already familiar to users as they are documented in Asio: __AsyncReadStream__, __AsyncWriteStream__, __SyncReadStream__, __SyncWriteStream__.
The type requirements for instantiating `beast::websocket::stream` versus `websocketpp::connection` with user defined types are vastly reduced (18 functions versus 2). Note that websocketpp connections are passed by `shared_ptr`. Beast does not use `shared_ptr` anywhere in its public interface. A `beast::websocket::stream` is constructible and movable in a manner identical to a `boost::asio::ip::tcp::socket`. Callers can put such objects in a `shared_ptr` if they want to, but there is no requirement to do so.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L234 websocketpp]] ][ [``` template<class NextLayer> class stream { NextLayer next_layer_; ... } ```] [``` template <typename config> class connection : public config::transport_type::transport_con_type , public config::connection_base { public: typedef lib::shared_ptr<type> ptr; ... } ```] ]]]]
[[3. Client and Server Role][
websocketpp provides multi-role support through a hierarchy of different classes. A `beast::websocket::stream` is role-agnostic, it offers member functions to perform both client and server handshakes in the same class. The same types are used for client and server streams.
[table [ [Beast] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/server_endpoint.hpp#L39 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/client_endpoint.hpp#L42 also]] ][ [ /<not needed>/ ] [``` template <typename config> class client : public endpoint<connection<config>,config>; template <typename config> class server : public endpoint<connection<config>,config>; ```] ]]]]
[[4. Thread Safety][
websocketpp uses mutexes to protect shared data from concurrent access. In contrast, Beast does not use mutexes anywhere in its implementation. Instead, it follows the Asio pattern. Calls to asynchronous initiation functions use the same method to invoke intermediate handlers as the method used to invoke the final handler, through the associated executor mechanism.
The only requirement in Beast is that calls to asynchronous initiation functions are made from the same implicit or explicit strand. For example, if the `io_context` associated with a `beast::websocket::stream` is single threaded, this counts as an implicit strand and no performance costs associated with mutexes are incurred.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/read_frame_op.ipp#L118 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L706 websocketpp]] ][ [``` mutex_type m_read_mutex; ```] ]]]]
[[5. Callback Model][
websocketpp requires a one-time call to set the handler for each event in its interface (for example, upon message receipt). The handler is represented by a `std::function` equivalent. Its important to recognize that the websocketpp interface performs type-erasure on this handler.
In comparison, Beast handlers are specified in a manner identical to Boost.Asio. They are function objects which can be copied or moved but most importantly they are not type erased. The compiler can see through the type directly to the implementation, permitting optimization. Furthermore, Beast follows the Asio rules for treatment of handlers. It respects any allocation, executors, cancellations associated with the handler through the use of argument dependent lookup overloads of functions such as `bind_allocaotr`.
The Beast completion handler is provided at the call site. For each call to an asynchronous initiation function, it is guaranteed that there will be exactly one final call to the handler. This functions exactly the same way as the asynchronous initiation functions found in Boost.Asio, allowing the composition of higher level abstractions.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L834 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L281 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L473 also]] ][ [``` template< class DynamicBuffer, // Supports user defined types class ReadHandler // Handler is NOT type-erased > typename async_completion< // Return value customization ReadHandler, // supports futures and coroutines void(error_code) >::result_type async_read( DynamicBuffer& dynabuf, ReadHandler&& handler); ```] [``` typedef lib::function< void(connection_hdl,message_ptr) > message_handler; void set_message_handler(message_handler h); ```] ]]]]
[[6. Extensible Asynchronous Model][
Beast fully supports the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf Extensible Asynchronous Model] developed by Christopher Kohlhoff, author of Boost.Asio (see Section 8).
Beast websocket asynchronous interfaces may be used seamlessly with `std::future` stackful/stackless coroutines, or user defined customizations.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/stream.ipp#L378 Beast]] [websocketpp] ][ [``` beast::async_completion< ReadHandler, void(error_code)> completion{handler}; read_op< DynamicBuffer, decltype(completion.handler)>{ completion.handler, *this, op, buffer};
return completion.result.get(); // Customization point ```] [ /<not available>/ ] ]]]]
[[7. Message Buffering][
websocketpp defines a message buffer, passed in arguments by `shared_ptr`, and an associated message manager which permits aggregation and reuse of memory. The implementation of `websocketpp::message` uses a `std::string` to hold the payload. If an incoming message is broken up into multiple frames, the string may be reallocated for each continuation frame. The `std::string` always uses the standard allocator, it is not possible to customize the choice of allocator.
Beast allows callers to specify the object for receiving the message or frame data, which is of any type meeting the requirements of __DynamicBuffer__ (modeled after `boost::asio::streambuf`).
Beast comes with the class __basic_multi_buffer__, an efficient implementation of the __DynamicBuffer__ concept which makes use of multiple allocated octet arrays. If an incoming message is broken up into multiple pieces, no reallocation occurs. Instead, new allocations are appended to the sequence when existing allocations are filled. Beast does not impose any particular memory management model on callers. The __basic_multi_buffer__ provided by beast supports standard allocators through a template argument. Use the __DynamicBuffer__ that comes with beast, customize the allocator if you desire, or provide your own type that meets the requirements.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/message_buffer/message.hpp#L78 websocketpp]] ][ [``` template<class DynamicBuffer> read(DynamicBuffer& dynabuf); ```] [``` template <template<class> class con_msg_manager> class message { public: typedef lib::shared_ptr<message> ptr; ... std::string m_payload; ... }; ```] ]]]]
[[8. Sending Messages][
When sending a message, websocketpp requires that the payload is packaged in a `websocketpp::message` object using `std::string` as the storage, or it requires a copy of the caller provided buffer by constructing a new message object. Messages are placed onto an outgoing queue. An asynchronous write operation runs in the background to clear the queue. No user facing handler can be registered to be notified when messages or frames have completed sending.
Beast doesn't allocate or make copies of buffers when sending data. The caller's buffers are sent in-place. You can use any object meeting the requirements of __ConstBufferSequence, permitting efficient scatter-gather I/O.
The [*ConstBufferSequence] interface allows callers to send data from memory-mapped regions (not possible in websocketpp). Callers can also use the same buffers to send data to multiple streams, for example broadcasting common subscription data to many clients at once. For each call to `async_write` the completion handler is called once when the data finishes sending, in a manner identical to `boost::asio::async_write`.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1048 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L672 websocketpp]] ][ [``` template<class ConstBufferSequence> void write(ConstBufferSequence const& buffers); ```] [``` lib::error_code send(std::string const & payload, frame::opcode::value op = frame::opcode::text); ... lib::error_code send(message_ptr msg); ```] ]]]]
[[9. Streaming Messages][
websocketpp requires that the entire message fit into memory, and that the size is known ahead of time.
Beast allows callers to compose messages in individual frames. This is useful when the size of the data is not known ahead of time or if it is not desired to buffer the entire message in memory at once before sending it. For example, sending periodic output of a database query running on a coroutine. Or sending the contents of a file in pieces, without bringing it all into memory.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1151 Beast]] [websocketpp] ][ [``` template<class ConstBufferSequence> void write_some(bool fin, ConstBufferSequence const& buffers); ```] [ /<not available>/ ] ]]]]
[[10. Flow Control][
The websocketpp read implementation continuously reads asynchronously from the network and buffers message data. To prevent unbounded growth and leverage TCP/IP's flow control mechanism, callers can periodically turn this 'read pump' off and back on.
In contrast a `beast::websocket::stream` does not independently begin background activity, nor does it buffer messages. It receives data only when there is a call to an asynchronous initiation function (for example `beast::websocket::stream::async_read`) with an associated handler. Applications do not need to implement explicit logic to regulate the flow of data. Instead, they follow the traditional model of issuing a read, receiving a read completion, processing the message, then issuing a new read and repeating the process.
[table [ [Beast] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L728 websocketpp]] ][ [ /<implicit>/ ] [``` lib::error_code pause_reading(); lib::error_code resume_reading(); ```] ]]]]
[[11. Connection Establishment][
websocketpp offers the `endpoint` class which can handle binding and listening to a port, and spawning connection objects.
Beast does not reinvent the wheel here, callers use the interfaces already in `boost::asio` for receiving incoming connections resolving host names, or establishing outgoing connections. After the socket (or `boost::asio::ssl::stream`) is connected, the `beast::websocket::stream` is constructed around it and the WebSocket handshake can be performed.
Beast users are free to implement their own "connection manager", but there is no requirement to do so.
[table [ [[@http://www.boost.org/doc/html/boost_asio/reference/async_connect.html Beast], [@http://www.boost.org/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html also]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/endpoint.hpp#L52 websocketpp]] ][ [``` #include <boost/asio.hpp> ```] [``` template <typename config> class endpoint : public config::socket_type; ```] ]]]]
[[12. WebSocket Handshaking][
Callers invoke `beast::websocket::accept` to perform the WebSocket handshake, but there is no requirement to use this function. Advanced users can perform the WebSocket handshake themselves. Beast WebSocket provides the tools for composing the request or response, and the Beast HTTP interface provides the container and algorithms for sending and receiving HTTP/1 messages including the necessary HTTP Upgrade request for establishing the WebSocket session.
Beast allows the caller to pass the incoming HTTP Upgrade request for the cases where the caller has already received an HTTP message. This flexibility permits novel and robust implementations. For example, a listening socket that can handshake in multiple protocols on the same port.
Sometimes callers want to read some bytes on the socket before reading the WebSocket HTTP Upgrade request. Beast allows these already-received bytes to be supplied to an overload of the accepting function to permit sophisticated features. For example, a listening socket that can accept both regular WebSocket and Secure WebSocket (SSL) connections.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L501 Beast], [@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L401 also]] [websocketpp] ][ [``` template<class ConstBufferSequence> void accept(ConstBufferSequence const& buffers);
template<class Allocator> void accept(http::header<true, http::basic_fields<Allocator>> const& req); ```] [ /<not available>/ ] ]]]]
variablelist
变量列表[[1. Synchronous Interface][
Beast offers full support for WebSockets using a synchronous interface. It uses the same style of interfaces found in Boost.Asio: versions that throw exceptions, or versions that return the error code in a reference parameter:
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [websocketpp] ][ [``` template<class DynamicBuffer> void read(DynamicBuffer& dynabuf) ```] [ /<not available>/ ] ]]]]
[[2. Connection Model][
websocketpp supports multiple transports by utilizing a trait, the `config::transport_type` ([@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/connection.hpp#L60 asio transport example]) To get an idea of the complexity involved with implementing a transport, compare the asio transport to the [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 `iostream` transport] (a layer that allows websocket communication over a `std::iostream`).
In contrast, Beast abstracts the transport by defining just one [*`NextLayer`] template argument The type requirements for [*`NextLayer`] are already familiar to users as they are documented in Asio: __AsyncReadStream__, __AsyncWriteStream__, __SyncReadStream__, __SyncWriteStream__.
The type requirements for instantiating `beast::websocket::stream` versus `websocketpp::connection` with user defined types are vastly reduced (18 functions versus 2). Note that websocketpp connections are passed by `shared_ptr`. Beast does not use `shared_ptr` anywhere in its public interface. A `beast::websocket::stream` is constructible and movable in a manner identical to a `boost::asio::ip::tcp::socket`. Callers can put such objects in a `shared_ptr` if they want to, but there is no requirement to do so.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L234 websocketpp]] ][ [``` template<class NextLayer> class stream { NextLayer next_layer_; ... } ```] [``` template <typename config> class connection : public config::transport_type::transport_con_type , public config::connection_base { public: typedef lib::shared_ptr<type> ptr; ... } ```] ]]]]
[[3. Client and Server Role][
websocketpp provides multi-role support through a hierarchy of different classes. A `beast::websocket::stream` is role-agnostic, it offers member functions to perform both client and server handshakes in the same class. The same types are used for client and server streams.
[table [ [Beast] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/server_endpoint.hpp#L39 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/client_endpoint.hpp#L42 also]] ][ [ /<not needed>/ ] [``` template <typename config> class client : public endpoint<connection<config>,config>; template <typename config> class server : public endpoint<connection<config>,config>; ```] ]]]]
[[4. Thread Safety][
websocketpp uses mutexes to protect shared data from concurrent access. In contrast, Beast does not use mutexes anywhere in its implementation. Instead, it follows the Asio pattern. Calls to asynchronous initiation functions use the same method to invoke intermediate handlers as the method used to invoke the final handler, through the associated executor mechanism.
The only requirement in Beast is that calls to asynchronous initiation functions are made from the same implicit or explicit strand. For example, if the `io_context` associated with a `beast::websocket::stream` is single threaded, this counts as an implicit strand and no performance costs associated with mutexes are incurred.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/read_frame_op.ipp#L118 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L706 websocketpp]] ][ [``` mutex_type m_read_mutex; ```] ]]]]
[[5. Callback Model][
websocketpp requires a one-time call to set the handler for each event in its interface (for example, upon message receipt). The handler is represented by a `std::function` equivalent. Its important to recognize that the websocketpp interface performs type-erasure on this handler.
In comparison, Beast handlers are specified in a manner identical to Boost.Asio. They are function objects which can be copied or moved but most importantly they are not type erased. The compiler can see through the type directly to the implementation, permitting optimization. Furthermore, Beast follows the Asio rules for treatment of handlers. It respects any allocation, executors, cancellations associated with the handler through the use of argument dependent lookup overloads of functions such as `bind_allocaotr`.
The Beast completion handler is provided at the call site. For each call to an asynchronous initiation function, it is guaranteed that there will be exactly one final call to the handler. This functions exactly the same way as the asynchronous initiation functions found in Boost.Asio, allowing the composition of higher level abstractions.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L834 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L281 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L473 also]] ][ [``` template< class DynamicBuffer, // Supports user defined types class ReadHandler // Handler is NOT type-erased > typename async_completion< // Return value customization ReadHandler, // supports futures and coroutines void(error_code) >::result_type async_read( DynamicBuffer& dynabuf, ReadHandler&& handler); ```] [``` typedef lib::function< void(connection_hdl,message_ptr) > message_handler; void set_message_handler(message_handler h); ```] ]]]]
[[6. Extensible Asynchronous Model][
Beast fully supports the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf Extensible Asynchronous Model] developed by Christopher Kohlhoff, author of Boost.Asio (see Section 8).
Beast websocket asynchronous interfaces may be used seamlessly with `std::future` stackful/stackless coroutines, or user defined customizations.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/stream.ipp#L378 Beast]] [websocketpp] ][ [``` beast::async_completion< ReadHandler, void(error_code)> completion{handler}; read_op< DynamicBuffer, decltype(completion.handler)>{ completion.handler, *this, op, buffer};
return completion.result.get(); // Customization point ```] [ /<not available>/ ] ]]]]
[[7. Message Buffering][
websocketpp defines a message buffer, passed in arguments by `shared_ptr`, and an associated message manager which permits aggregation and reuse of memory. The implementation of `websocketpp::message` uses a `std::string` to hold the payload. If an incoming message is broken up into multiple frames, the string may be reallocated for each continuation frame. The `std::string` always uses the standard allocator, it is not possible to customize the choice of allocator.
Beast allows callers to specify the object for receiving the message or frame data, which is of any type meeting the requirements of __DynamicBuffer__ (modeled after `boost::asio::streambuf`).
Beast comes with the class __basic_multi_buffer__, an efficient implementation of the __DynamicBuffer__ concept which makes use of multiple allocated octet arrays. If an incoming message is broken up into multiple pieces, no reallocation occurs. Instead, new allocations are appended to the sequence when existing allocations are filled. Beast does not impose any particular memory management model on callers. The __basic_multi_buffer__ provided by beast supports standard allocators through a template argument. Use the __DynamicBuffer__ that comes with beast, customize the allocator if you desire, or provide your own type that meets the requirements.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/message_buffer/message.hpp#L78 websocketpp]] ][ [``` template<class DynamicBuffer> read(DynamicBuffer& dynabuf); ```] [``` template <template<class> class con_msg_manager> class message { public: typedef lib::shared_ptr<message> ptr; ... std::string m_payload; ... }; ```] ]]]]
[[8. Sending Messages][
When sending a message, websocketpp requires that the payload is packaged in a `websocketpp::message` object using `std::string` as the storage, or it requires a copy of the caller provided buffer by constructing a new message object. Messages are placed onto an outgoing queue. An asynchronous write operation runs in the background to clear the queue. No user facing handler can be registered to be notified when messages or frames have completed sending.
Beast doesn't allocate or make copies of buffers when sending data. The caller's buffers are sent in-place. You can use any object meeting the requirements of __ConstBufferSequence, permitting efficient scatter-gather I/O.
The [*ConstBufferSequence] interface allows callers to send data from memory-mapped regions (not possible in websocketpp). Callers can also use the same buffers to send data to multiple streams, for example broadcasting common subscription data to many clients at once. For each call to `async_write` the completion handler is called once when the data finishes sending, in a manner identical to `boost::asio::async_write`.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1048 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L672 websocketpp]] ][ [``` template<class ConstBufferSequence> void write(ConstBufferSequence const& buffers); ```] [``` lib::error_code send(std::string const & payload, frame::opcode::value op = frame::opcode::text); ... lib::error_code send(message_ptr msg); ```] ]]]]
[[9. Streaming Messages][
websocketpp requires that the entire message fit into memory, and that the size is known ahead of time.
Beast allows callers to compose messages in individual frames. This is useful when the size of the data is not known ahead of time or if it is not desired to buffer the entire message in memory at once before sending it. For example, sending periodic output of a database query running on a coroutine. Or sending the contents of a file in pieces, without bringing it all into memory.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1151 Beast]] [websocketpp] ][ [``` template<class ConstBufferSequence> void write_some(bool fin, ConstBufferSequence const& buffers); ```] [ /<not available>/ ] ]]]]
[[10. Flow Control][
The websocketpp read implementation continuously reads asynchronously from the network and buffers message data. To prevent unbounded growth and leverage TCP/IP's flow control mechanism, callers can periodically turn this 'read pump' off and back on.
In contrast a `beast::websocket::stream` does not independently begin background activity, nor does it buffer messages. It receives data only when there is a call to an asynchronous initiation function (for example `beast::websocket::stream::async_read`) with an associated handler. Applications do not need to implement explicit logic to regulate the flow of data. Instead, they follow the traditional model of issuing a read, receiving a read completion, processing the message, then issuing a new read and repeating the process.
[table [ [Beast] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L728 websocketpp]] ][ [ /<implicit>/ ] [``` lib::error_code pause_reading(); lib::error_code resume_reading(); ```] ]]]]
[[11. Connection Establishment][
websocketpp offers the `endpoint` class which can handle binding and listening to a port, and spawning connection objects.
Beast does not reinvent the wheel here, callers use the interfaces already in `boost::asio` for receiving incoming connections resolving host names, or establishing outgoing connections. After the socket (or `boost::asio::ssl::stream`) is connected, the `beast::websocket::stream` is constructed around it and the WebSocket handshake can be performed.
Beast users are free to implement their own "connection manager", but there is no requirement to do so.
[table [ [[@http://www.boost.org/doc/html/boost_asio/reference/async_connect.html Beast], [@http://www.boost.org/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html also]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/endpoint.hpp#L52 websocketpp]] ][ [``` #include <boost/asio.hpp> ```] [``` template <typename config> class endpoint : public config::socket_type; ```] ]]]]
[[12. WebSocket Handshaking][
Callers invoke `beast::websocket::accept` to perform the WebSocket handshake, but there is no requirement to use this function. Advanced users can perform the WebSocket handshake themselves. Beast WebSocket provides the tools for composing the request or response, and the Beast HTTP interface provides the container and algorithms for sending and receiving HTTP/1 messages including the necessary HTTP Upgrade request for establishing the WebSocket session.
Beast allows the caller to pass the incoming HTTP Upgrade request for the cases where the caller has already received an HTTP message. This flexibility permits novel and robust implementations. For example, a listening socket that can handshake in multiple protocols on the same port.
Sometimes callers want to read some bytes on the socket before reading the WebSocket HTTP Upgrade request. Beast allows these already-received bytes to be supplied to an overload of the accepting function to permit sophisticated features. For example, a listening socket that can accept both regular WebSocket and Secure WebSocket (SSL) connections.
[table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L501 Beast], [@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L401 also]] [websocketpp] ][ [``` template<class ConstBufferSequence> void accept(ConstBufferSequence const& buffers);
template<class Allocator> void accept(http::header<true, http::basic_fields<Allocator>> const& req); ```] [ /<not available
[[1. 同步接口][
Beast 提供了对 WebSocket 的全面支持,采用同步接口。它使用与 Boost.Asio 中相同的接口风格:抛出异常的版本,以及通过引用参数返回错误码的版本。
[表格 [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [websocketpp] ][ [template<class DynamicBuffer> void read(DynamicBuffer& dynabuf)] [ /<不可用>/ ] ]]]]
[[2. 连接模型][
WebSocketpp 通过使用一种特质——config::transport_type——支持多种传输方式(参见[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/connection.hpp#L60 asio传输示例])。若想了解实现传输的复杂性,可对比一下asio传输与[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 iostream传输](这是一种允许通过std::iostream进行WebSocket通信的层)。
相比之下,Beast通过仅定义一个[NextLayer]模板参数来抽象传输。[NextLayer]的类型要求对用户而言早已熟悉,因为这些要求已在Asio中进行了文档化:AsyncReadStream、AsyncWriteStream、SyncReadStream、SyncWriteStream。
使用用户自定义类型实例化beast::websocket::stream与websocketpp::connection时,类型要求大幅降低(从18个函数降至2个)。需要注意的是,websocketpp连接是以shared_ptr形式传递的。而Beast在其公共接口中任何地方均未使用shared_ptr。beast::websocket::stream的构造和移动方式与boost::asio::ip::tcp::socket完全一致。调用者如果需要,可以将此类对象放入shared_ptr中,但并非必须如此。 [表格 [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L234 websocketpp]] ][ [template<class NextLayer> class stream { NextLayer next_layer_; ... }] [template <typename config> class connection : public config::transport_type::transport_con_type , public config::connection_base { public: typedef lib::shared_ptr<type> ptr; ... }] ]]]]
[[3. 客户端与服务器角色][
WebSocketpp 通过不同类别的层次结构提供了多角色支持。beast::websocket::stream 不依赖于特定角色,它在同一类中提供成员函数,以同时执行客户端和服务器的握手操作。客户端和服务器流均使用相同的类型。
[表格 [ [兽] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/server_endpoint.hpp#L39 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/client_endpoint.hpp#L42 同样]] ][ [ /<无需填写>/ ] [模板 <typename 配置> 类客户端 : 公共 endpoint<连接<配置>,配置>; 模板 <typename 配置> 类服务器 : 公共 endpoint<连接<配置>,配置>;] ]]]]
[[4. 线程安全][
WebSocketpp 使用互斥锁来保护共享数据,防止并发访问。相比之下,Beast 在其整个实现中并未使用任何互斥锁。相反,它遵循了Asio模式:对异步启动函数的调用,采用与调用最终处理程序相同的机制,即通过关联的执行器机制来调用中间处理程序。 Beast的唯一要求是,对异步启动函数的调用必须来自同一隐式或显式线程。例如,如果与beast::websocket::stream关联的io_context是单线程的,则这被视为隐式线程,因此不会产生与互斥锁相关的性能开销。
[表格 [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/read_frame_op.ipp#L118 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L706 websocketpp]] ][ [mutex_type m_read_mutex;] ]]]]
[[5. 回调模型][
websocketpp 需要对其实现接口中的每个事件(例如,消息接收时)进行一次调用,以设置相应的处理程序。该处理程序由一个等效于 std::function 的对象表示。需要注意的是,websocketpp 接口会对此处理程序执行类型擦除操作。
相比之下,Beast处理器的定义方式与Boost.Asio完全一致。它们是函数对象,可以进行复制或移动操作,但最重要的是,它们不会进行类型擦除。编译器能够直接通过类型识别其实现细节,从而实现优化。此外,Beast遵循Asio关于处理器处理的规则:它会通过使用基于参数依赖查找的函数重载(例如bind_allocator),尊重与处理器相关联的任何分配、执行器和取消操作。 在调用站点提供了“兽”完成处理程序。对于每次对异步启动函数的调用,都保证恰好会有一 次对该处理程序的最终调用。此功能与Boost.Asio中提供的异步启动函数完全相同,从而支持更高级别抽象的组合。 [表格 [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L834 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L281 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L473 也]] ][ [模板< 类型 DynamicBuffer, // 支持用户自定义类型 类型 ReadHandler // 处理器不进行类型擦除 > typename async_completion< // 返回值定制 ReadHandler, // 支持 futures 和协程 void(error_code) >::result_type async_read( DynamicBuffer& dynabuf, ReadHandler&& handler);] [使用 lib::function< void(connection_hdl,message_ptr) > message_handler; void set_message_handler(message_handler h);] ]]]]
[[6. 可扩展的异步模型][
Beast完全支持由Boost.Asio作者克里斯托弗·科尔霍夫所开发的[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf 可扩展异步模型](参见第8节)。
Beast WebSocket 异步接口可与 std::future 栈式/非栈式协程,或用户自定义的定制化功能无缝配合使用。
[表格 [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/stream.ipp#L378 Beast]] [websocketpp] ][ [``` beast::async_completion< ReadHandler, void(error_code)> completion{handler}; read_op< DynamicBuffer, decltype(completion.handler)>{ completion.handler, *this, op, buffer};
返回 completion.result.get(); // 自定义点 ```] [ /<不可用>/ ] ]]]]
[[7. 消息缓冲][
websocketpp 定义了一个消息缓冲区,通过 shared_ptr 作为参数传入,并配备了一个关联的消息管理器,该管理器允许对内存进行聚合和复用。websocketpp::message 的实现使用了 std::string 来存储有效载荷。如果接收到的消息被拆分为多个帧,那么对于每个后续帧,该字符串都可能重新分配内存。std::string 始终使用标准分配器,无法自定义分配器的选择。
Beast 允许调用者指定用于接收消息或帧数据的对象,该对象可以是任何符合__DynamicBuffer__要求的类型(仿照 boost::asio::streambuf 实现)。
Beast 提供了类 basic_multi_buffer,这是对 DynamicBuffer 概念的一种高效实现,它利用了多个已分配的字节数组。如果传入的消息被拆分成多个片段,则不会发生重新分配;相反,当现有分配空间填满时,会向序列中追加新的分配。Beast 不会对调用方强加任何特定的内存管理模型。Beast 提供的 basic_multi_buffer 通过模板参数支持标准分配器。您可以直接使用 Beast 自带的 DynamicBuffer,也可以根据需要自定义分配器,或者提供符合要求的自定义类型。
[表格 [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/message_buffer/message.hpp#L78 websocketpp]] ][ [模板<class DynamicBuffer> 读取(DynamicBuffer& dynabuf);] [模板<模板<class> class con_msg_manager> 类消息 { public: typedef lib::shared_ptr<消息> ptr; ... std::string m_payload; ... };] ]]]]
[[8. 发送消息][
发送消息时,websocketpp要求将有效载荷封装在websocketpp::message对象中,存储方式为std::string;或者,通过构造一个新的消息对象来复制调用方提供的缓冲区。消息会被放入一个待发送队列中。后台会执行异步写操作以清空该队列。无法注册任何面向用户的处理程序,以在消息或帧发送完成时获得通知。
Beast 在发送数据时不会分配或复制缓冲区。调用方的缓冲区将就地发送。您可以使用任何符合__ConstBufferSequence要求的对象,从而实现高效的分散-收集 I/O 操作。
[*ConstBufferSequence] 接口允许调用方从内存映射区域发送数据(在 websocketpp 中无法实现)。调用方还可使用相同的缓冲区向多个流发送数据,例如一次性将通用订阅数据广播给多个客户端。每次调用 async_write 时,完成处理程序都会在数据发送完毕后被调用一次,其调用方式与 boost::asio::async_write 完全相同。
[表格 [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1048 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L672 websocketpp]] ][ [template<class ConstBufferSequence> void write(ConstBufferSequence const& buffers);] [lib::error_code send(std::string const & payload, frame::opcode::value op = frame::opcode::text); ... lib::error_code send(message_ptr msg);] ]]]]
[[9. 流式消息][
WebSocketpp要求整个消息必须能够完整地放入内存中,且其大小需事先已知。
Beast 允许呼叫方以单独的帧来组成消息。当数据大小事先未知,或者不希望在发送前将整个消息一次性缓冲到内存中时,这一点非常有用。例如,定期输出协程中运行的数据库查询结果;或分块发送文件内容,而无需将其全部加载到内存中。
[表格 [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1151 Beast]] [websocketpp] ][ [template<class ConstBufferSequence> void write_some(bool fin, ConstBufferSequence const& buffers);] [ /<不可用>/ ] ]]]]
[[10. 流量控制][
websocketpp 的读取实现会持续从网络异步读取数据,并将消息数据缓存起来。为防止缓存无限制增长并利用 TCP/IP 的流量控制机制,调用方可以定期关闭和重新开启这一“读取泵”。
相比之下,beast::websocket::stream 不会独立启动后台活动,也不会对消息进行缓冲。它仅在调用异步初始化函数(例如 beast::websocket::stream::async_read)并附带相应处理程序时才接收数据。应用程序无需实现显式的逻辑来控制数据流。相反,它们遵循传统的模式:发出读取请求,等待读取完成,处理接收到的消息,然后再次发出读取请求,如此循环往复。
[表格 [ [兽] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L728 websocketpp]] ][ [ /<隐式>/ ] [lib::error_code pause_reading(); lib::error_code resume_reading();] ]]]]
[[11. 连接建立][
websocketpp 提供了 endpoint 类,该类可处理端口的绑定与监听,并创建连接对象。
Beast并未在此处重新发明轮子;调用方直接使用boost::asio中已有的接口来接收传入连接、解析主机名,或建立出站连接。在套接字(或boost::asio::ssl::stream)连接成功后,便可在其基础上构造beast::websocket::stream,从而完成WebSocket握手过程。
Beast 用户可自由实现自己的“连接管理器”,但并无强制要求必须这么做。
[表格 [ [[@http://www.boost.org/doc/html/boost_asio/reference/async_connect.html Beast], [@http://www.boost.org/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html 也]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/endpoint.hpp#L52 websocketpp]] ][ [#include <boost/asio.hpp>] [template <typename config> class endpoint : public config::socket_type;] ]]]]
[[12. WebSocket 握手][
调用方可调用beast::websocket::accept来执行WebSocket握手,但并无强制要求必须使用此函数。高级用户可自行完成WebSocket握手。Beast WebSocket提供了用于构造请求或响应的工具,而Beast HTTP接口则提供了用于发送和接收HTTP/1消息的容器与算法,其中包括建立WebSocket会话所必需的HTTP Upgrade请求。 Beast 允许调用方在已接收到 HTTP 消息的情况下,将传入的 HTTP 升级请求传递出去。这种灵活性使得实现方式更加新颖且稳健。例如,一个监听套接字可以在同一端口上支持多种协议的握手过程。
有时,呼叫方希望在读取WebSocket HTTP升级请求之前,先从套接字中读取一些字节。Beast允许将这些已接收的字节提供给接受函数的一个重载版本,从而实现复杂的功能。例如,一个监听套接字既可以接受常规WebSocket连接,也可以接受安全WebSocket(SSL)连接。
[表格 [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L501 Beast], [@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L401 同样]] [websocketpp] ][ [``` 模板 void accept(ConstBufferSequence const& buffers);
template void accept(http::header<true, http::basic_fields> const& req); ```] [ /<不可用>/ ] ]]]]