3_websocket_zaphoyd.qbk 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. [/
  2. Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. Official repository: https://github.com/boostorg/beast
  6. ]
  7. [section Comparison to Zaphoyd Studios WebSocket++]
  8. [variablelist
  9. [[
  10. How does this compare to [@https://www.zaphoyd.com/websocketpp websocketpp],
  11. an alternate header-only WebSocket implementation?
  12. ][
  13. [variablelist
  14. [[1. Synchronous Interface][
  15. Beast offers full support for WebSockets using a synchronous interface. It
  16. uses the same style of interfaces found in Boost.Asio: versions that throw
  17. exceptions, or versions that return the error code in a reference parameter:
  18. [table
  19. [
  20. [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]]
  21. [websocketpp]
  22. ][
  23. [```
  24. template<class DynamicBuffer>
  25. void
  26. read(DynamicBuffer& dynabuf)
  27. ```]
  28. [
  29. /<not available>/
  30. ]
  31. ]]]]
  32. [[2. Connection Model][
  33. websocketpp supports multiple transports by utilizing a trait, the `config::transport_type`
  34. ([@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/connection.hpp#L60 asio transport example])
  35. To get an idea of the complexity involved with implementing a transport,
  36. compare the asio transport to the
  37. [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 `iostream` transport]
  38. (a layer that allows websocket communication over a `std::iostream`).
  39. In contrast, Beast abstracts the transport by defining just one [*`NextLayer`]
  40. template argument The type requirements for [*`NextLayer`] are
  41. already familiar to users as they are documented in Asio:
  42. __AsyncReadStream__, __AsyncWriteStream__, __SyncReadStream__, __SyncWriteStream__.
  43. The type requirements for instantiating `beast::websocket::stream` versus
  44. `websocketpp::connection` with user defined types are vastly reduced
  45. (18 functions versus 2). Note that websocketpp connections are passed by
  46. `shared_ptr`. Beast does not use `shared_ptr` anywhere in its public interface.
  47. A `beast::websocket::stream` is constructible and movable in a manner identical
  48. to a `boost::asio::ip::tcp::socket`. Callers can put such objects in a
  49. `shared_ptr` if they want to, but there is no requirement to do so.
  50. [table
  51. [
  52. [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp Beast]]
  53. [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L234 websocketpp]]
  54. ][
  55. [```
  56. template<class NextLayer>
  57. class stream
  58. {
  59. NextLayer next_layer_;
  60. ...
  61. }
  62. ```]
  63. [```
  64. template <typename config>
  65. class connection
  66. : public config::transport_type::transport_con_type
  67. , public config::connection_base
  68. {
  69. public:
  70. typedef lib::shared_ptr<type> ptr;
  71. ...
  72. }
  73. ```]
  74. ]]]]
  75. [[3. Client and Server Role][
  76. websocketpp provides multi-role support through a hierarchy of
  77. different classes. A `beast::websocket::stream` is role-agnostic, it
  78. offers member functions to perform both client and server handshakes
  79. in the same class. The same types are used for client and server
  80. streams.
  81. [table
  82. [
  83. [Beast]
  84. [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/server_endpoint.hpp#L39 websocketpp],
  85. [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/client_endpoint.hpp#L42 also]]
  86. ][
  87. [
  88. /<not needed>/
  89. ]
  90. [```
  91. template <typename config>
  92. class client : public endpoint<connection<config>,config>;
  93. template <typename config>
  94. class server : public endpoint<connection<config>,config>;
  95. ```]
  96. ]]]]
  97. [[4. Thread Safety][
  98. websocketpp uses mutexes to protect shared data from concurrent
  99. access. In contrast, Beast does not use mutexes anywhere in its
  100. implementation. Instead, it follows the Asio pattern. Calls to
  101. asynchronous initiation functions use the same method to invoke
  102. intermediate handlers as the method used to invoke the final handler,
  103. through the __asio_handler_invoke__ mechanism.
  104. The only requirement in Beast is that calls to asynchronous initiation
  105. functions are made from the same implicit or explicit strand. For
  106. example, if the `io_context` associated with a `beast::websocket::stream`
  107. is single threaded, this counts as an implicit strand and no performance
  108. costs associated with mutexes are incurred.
  109. [table
  110. [
  111. [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/read_frame_op.ipp#L118 Beast]]
  112. [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L706 websocketpp]]
  113. ][
  114. [```
  115. template <class Function>
  116. friend
  117. void asio_handler_invoke(Function&& f, read_frame_op* op)
  118. {
  119. return boost_asio_handler_invoke_helpers::invoke(f, op->d_->h);
  120. }
  121. ```]
  122. [```
  123. mutex_type m_read_mutex;
  124. ```]
  125. ]]]]
  126. [[5. Callback Model][
  127. websocketpp requires a one-time call to set the handler for each event
  128. in its interface (for example, upon message receipt). The handler is
  129. represented by a `std::function` equivalent. Its important to recognize
  130. that the websocketpp interface performs type-erasure on this handler.
  131. In comparison, Beast handlers are specified in a manner identical to
  132. Boost.Asio. They are function objects which can be copied or moved but
  133. most importantly they are not type erased. The compiler can see
  134. through the type directly to the implementation, permitting
  135. optimization. Furthermore, Beast follows the Asio rules for treatment
  136. of handlers. It respects any allocation, continuation, or invocation
  137. customizations associated with the handler through the use of argument
  138. dependent lookup overloads of functions such as `asio_handler_allocate`.
  139. The Beast completion handler is provided at the call site. For each
  140. call to an asynchronous initiation function, it is guaranteed that
  141. there will be exactly one final call to the handler. This functions
  142. exactly the same way as the asynchronous initiation functions found in
  143. Boost.Asio, allowing the composition of higher level abstractions.
  144. [table
  145. [
  146. [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L834 Beast]]
  147. [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L281 websocketpp],
  148. [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L473 also]]
  149. ][
  150. [```
  151. template<
  152. class DynamicBuffer, // Supports user defined types
  153. class ReadHandler // Handler is NOT type-erased
  154. >
  155. typename async_completion< // Return value customization
  156. ReadHandler, // supports futures and coroutines
  157. void(error_code)
  158. >::result_type
  159. async_read(
  160. DynamicBuffer& dynabuf,
  161. ReadHandler&& handler);
  162. ```]
  163. [```
  164. typedef lib::function<
  165. void(connection_hdl,message_ptr)
  166. > message_handler;
  167. void set_message_handler(message_handler h);
  168. ```]
  169. ]]]]
  170. [[6. Extensible Asynchronous Model][
  171. Beast fully supports the
  172. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf Extensible Asynchronous Model]
  173. developed by Christopher Kohlhoff, author of Boost.Asio (see Section 8).
  174. Beast websocket asynchronous interfaces may be used seamlessly with
  175. `std::future` stackful/stackless coroutines, or user defined customizations.
  176. [table
  177. [
  178. [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/stream.ipp#L378 Beast]]
  179. [websocketpp]
  180. ][
  181. [```
  182. beast::async_completion<
  183. ReadHandler,
  184. void(error_code)> completion{handler};
  185. read_op<
  186. DynamicBuffer, decltype(completion.handler)>{
  187. completion.handler, *this, op, buffer};
  188. return completion.result.get(); // Customization point
  189. ```]
  190. [
  191. /<not available>/
  192. ]
  193. ]]]]
  194. [[7. Message Buffering][
  195. websocketpp defines a message buffer, passed in arguments by
  196. `shared_ptr`, and an associated message manager which permits
  197. aggregation and reuse of memory. The implementation of
  198. `websocketpp::message` uses a `std::string` to hold the payload. If an
  199. incoming message is broken up into multiple frames, the string may be
  200. reallocated for each continuation frame. The `std::string` always uses
  201. the standard allocator, it is not possible to customize the choice of
  202. allocator.
  203. Beast allows callers to specify the object for receiving the message
  204. or frame data, which is of any type meeting the requirements of
  205. __DynamicBuffer__ (modeled after `boost::asio::streambuf`).
  206. Beast comes with the class __basic_multi_buffer__, an efficient
  207. implementation of the __DynamicBuffer__ concept which makes use of multiple
  208. allocated octet arrays. If an incoming message is broken up into
  209. multiple pieces, no reallocation occurs. Instead, new allocations are
  210. appended to the sequence when existing allocations are filled. Beast
  211. does not impose any particular memory management model on callers. The
  212. __basic_multi_buffer__ provided by beast supports standard allocators through
  213. a template argument. Use the __DynamicBuffer__ that comes with beast,
  214. customize the allocator if you desire, or provide your own type that
  215. meets the requirements.
  216. [table
  217. [
  218. [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]]
  219. [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/message_buffer/message.hpp#L78 websocketpp]]
  220. ][
  221. [```
  222. template<class DynamicBuffer>
  223. read(DynamicBuffer& dynabuf);
  224. ```]
  225. [```
  226. template <template<class> class con_msg_manager>
  227. class message {
  228. public:
  229. typedef lib::shared_ptr<message> ptr;
  230. ...
  231. std::string m_payload;
  232. ...
  233. };
  234. ```]
  235. ]]]]
  236. [[8. Sending Messages][
  237. When sending a message, websocketpp requires that the payload is
  238. packaged in a `websocketpp::message` object using `std::string` as the
  239. storage, or it requires a copy of the caller provided buffer by
  240. constructing a new message object. Messages are placed onto an
  241. outgoing queue. An asynchronous write operation runs in the background
  242. to clear the queue. No user facing handler can be registered to be
  243. notified when messages or frames have completed sending.
  244. Beast doesn't allocate or make copies of buffers when sending data. The
  245. caller's buffers are sent in-place. You can use any object meeting the
  246. requirements of __ConstBufferSequence, permitting efficient scatter-gather I/O.
  247. The [*ConstBufferSequence] interface allows callers to send data from
  248. memory-mapped regions (not possible in websocketpp). Callers can also
  249. use the same buffers to send data to multiple streams, for example
  250. broadcasting common subscription data to many clients at once. For
  251. each call to `async_write` the completion handler is called once when
  252. the data finishes sending, in a manner identical to `boost::asio::async_write`.
  253. [table
  254. [
  255. [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1048 Beast]]
  256. [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L672 websocketpp]]
  257. ][
  258. [```
  259. template<class ConstBufferSequence>
  260. void
  261. write(ConstBufferSequence const& buffers);
  262. ```]
  263. [```
  264. lib::error_code send(std::string const & payload,
  265. frame::opcode::value op = frame::opcode::text);
  266. ...
  267. lib::error_code send(message_ptr msg);
  268. ```]
  269. ]]]]
  270. [[9. Streaming Messages][
  271. websocketpp requires that the entire message fit into memory, and that
  272. the size is known ahead of time.
  273. Beast allows callers to compose messages in individual frames. This is
  274. useful when the size of the data is not known ahead of time or if it
  275. is not desired to buffer the entire message in memory at once before
  276. sending it. For example, sending periodic output of a database query
  277. running on a coroutine. Or sending the contents of a file in pieces,
  278. without bringing it all into memory.
  279. [table
  280. [
  281. [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1151 Beast]]
  282. [websocketpp]
  283. ][
  284. [```
  285. template<class ConstBufferSequence>
  286. void
  287. write_some(bool fin,
  288. ConstBufferSequence const& buffers);
  289. ```]
  290. [
  291. /<not available>/
  292. ]
  293. ]]]]
  294. [[10. Flow Control][
  295. The websocketpp read implementation continuously reads asynchronously
  296. from the network and buffers message data. To prevent unbounded growth
  297. and leverage TCP/IP's flow control mechanism, callers can periodically
  298. turn this 'read pump' off and back on.
  299. In contrast a `beast::websocket::stream` does not independently begin
  300. background activity, nor does it buffer messages. It receives data only
  301. when there is a call to an asynchronous initiation function (for
  302. example `beast::websocket::stream::async_read`) with an associated handler.
  303. Applications do not need to implement explicit logic to regulate the
  304. flow of data. Instead, they follow the traditional model of issuing a
  305. read, receiving a read completion, processing the message, then
  306. issuing a new read and repeating the process.
  307. [table
  308. [
  309. [Beast]
  310. [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L728 websocketpp]]
  311. ][
  312. [
  313. /<implicit>/
  314. ]
  315. [```
  316. lib::error_code pause_reading();
  317. lib::error_code resume_reading();
  318. ```]
  319. ]]]]
  320. [[11. Connection Establishment][
  321. websocketpp offers the `endpoint` class which can handle binding and
  322. listening to a port, and spawning connection objects.
  323. Beast does not reinvent the wheel here, callers use the interfaces
  324. already in `boost::asio` for receiving incoming connections resolving
  325. host names, or establishing outgoing connections. After the socket (or
  326. `boost::asio::ssl::stream`) is connected, the `beast::websocket::stream`
  327. is constructed around it and the WebSocket handshake can be performed.
  328. Beast users are free to implement their own "connection manager", but
  329. there is no requirement to do so.
  330. [table
  331. [
  332. [[@http://www.boost.org/doc/html/boost_asio/reference/async_connect.html Beast],
  333. [@http://www.boost.org/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html also]]
  334. [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/endpoint.hpp#L52 websocketpp]]
  335. ][
  336. [```
  337. #include <boost/asio.hpp>
  338. ```]
  339. [```
  340. template <typename config>
  341. class endpoint : public config::socket_type;
  342. ```]
  343. ]]]]
  344. [[12. WebSocket Handshaking][
  345. Callers invoke `beast::websocket::accept` to perform the WebSocket
  346. handshake, but there is no requirement to use this function. Advanced
  347. users can perform the WebSocket handshake themselves. Beast WebSocket
  348. provides the tools for composing the request or response, and the
  349. Beast HTTP interface provides the container and algorithms for sending
  350. and receiving HTTP/1 messages including the necessary HTTP Upgrade
  351. request for establishing the WebSocket session.
  352. Beast allows the caller to pass the incoming HTTP Upgrade request for
  353. the cases where the caller has already received an HTTP message.
  354. This flexibility permits novel and robust implementations. For example,
  355. a listening socket that can handshake in multiple protocols on the
  356. same port.
  357. Sometimes callers want to read some bytes on the socket before reading
  358. the WebSocket HTTP Upgrade request. Beast allows these already-received
  359. bytes to be supplied to an overload of the accepting function to permit
  360. sophisticated features. For example, a listening socket that can
  361. accept both regular WebSocket and Secure WebSocket (SSL) connections.
  362. [table
  363. [
  364. [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L501 Beast],
  365. [@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L401 also]]
  366. [websocketpp]
  367. ][
  368. [```
  369. template<class ConstBufferSequence>
  370. void
  371. accept(ConstBufferSequence const& buffers);
  372. template<class Allocator>
  373. void
  374. accept(http::header<true, http::basic_fields<Allocator>> const& req);
  375. ```]
  376. [
  377. /<not available>/
  378. ]
  379. ]]]]
  380. ]
  381. ]]
  382. ]
  383. [endsect]