Let's say we have a websocket client based on boost::beast. At some point we want to send a ping frame to the server. To do this, boost::beast::websocket::stream offers two options:
ping methodasync_ping methodI want to know how to use these methods correctly in an asynchronous environment.
ping or async_ping if there is an outstanding (incompleted) async_write operation?ping seems preferable to async_ping because async_ping requires us to ensure that there are no outstanding ping, pong, async_ping, or async_pong operations when it is called. If I decide to use async_ping, what is the correct way to call it?ping (because ping is easy in use), how long can a synchronous ping call theoretically take? Could this be a bottleneck in an asynchronous application?Which of these approaches is preferable to use in an asynchronous environment and how to implement it correctly?
Please note that I am working in a single-threaded but asynchronous environment.
You didn't ask, but mixing async_XXX and synchronous calls is not supported by beast::websocket::stream.
No. [async_]ping() and [async_]close count as caller-initiated-write-operations. These must not be overlapped with other caller-initiated-write-operations.
As far as automatic control frame behavior is concerned, these do not compete with caller-initiated-write-operations, this is documented here
During read operations, Beast automatically reads and processes control frames. If a control callback is registered, the callback is notified of the incoming control frame. The implementation will respond to pings automatically. The receipt of a close frame initiates the WebSocket close procedure, eventually resulting in the error code error::closed being delivered to the caller in a subsequent read operation, assuming no other error takes place.
However, these writes will not compete with caller-initiated write operations. For the purposes of correctness with respect to the stream invariants, caller-initiated read operations still only count as a read. This means that callers can have a simultaneously active read, write, and ping/pong operation in progress, while the implementation also automatically handles control frames.
As mentioned above, in async context ping() is out of the question. async_ping should be queued. My recommendation: the best way to do ping is probably: not at all. I have yet to think of a reason why it would help. Also see e.g. How to use SO_KEEPALIVE option properly to detect that the client at the other end is down?
You can't. How long ping() can take depends (only) on the peer implementation. See also Auto-fragment
For some inspiration, beyond making a barrage of isolated questions consider looking at existing examples. E.g. I've recently answered a similar question to show how close operations (so, using async_close) are write operations as well, and how to elegantly combine them with a write queue: WebSocket async_close fails with "Operation canceled" in destructor (Boost.Beast)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With