0

I am sending data on a boost::beast::websocket

I would like to send the data synchronously, so am trying to decide if I should use write or write_some.

From this SO answer (which is about asio rather than beast specifically, but I assume(!) the same rules apply?) I understand that write will block until the entire message is confirmed sent, whereas write_some may return early, and will return the number of bytes sent which may not be all the bytes which were requested be sent.

In my particular use-case I am using a single thread, and the write is done from within this thread's context (ie: from inside a callback issued after entering io_context.run())

Since I don't want to block the caller for some indeterminate amount of time, I want to avoid using write if there is a more elegant solution.

So if I then turn to async_write, I am uncertain what I should do if the number of bytes is less than the number of bytes I requested be sent?

How I would normally handle this with standard tcp sockets is use non-blocking mode, and when I get back EWOULDBLOCK, enqueue the data and carry on. When the socket becomes writeable again, only then complete the write (much akin to an asio async_write). Since non-blocking is not supported in beast, I'm wondering what the analogous approach is?

Presumably I need to perform some additional write operation to ensure the rest of the bytes are sent in due course?

The beast docs say

Callers are responsible for synchronizing operations on the socket using an implicit or explicit strand, as per the Asio documentation. The websocket stream asynchronous interface supports one of each of the following operations to be active at the same time:

async_read or async_read_some
async_write or async_write_some
async_ping or async_pong
async_close

Is it ok to start an async write of the remaining bytes, so long as I ensure that a new synchronous write/write_some isn't started before the outstanding async write has completed?

If I cannot start an async write to complete the send of the remaining bytes, how is one supposed to handle a synchronous write_some which doesn't completely send all bytes?

As to why I don't just use async_write always, I have additional slow processing to do after the attempt to write, such as logging etc. Since I am using a single thread, and the call to async_write happens within that thread, the write will only occur after I return control to the event loop.

So what I'd like to do is attempt to write synchronously (which will work in 90% of the cases) so the data is sent, and then perform my slow tasks which would otherwise delay the write. In the 10% of cases where a sync write doesn't complete immediately, then an alternative async_write operation should be employed - but only in the fallback situation.

Possibly related: I see that write_some has a flag fin, which should be set to true if this is the last part of the message.

I am only ever attempting to write complete messages, so should I always use true for this?

Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213
  • If you have a fixed amount of data to send just use `*write`and let asio take care of writing all the data – Alan Birtles May 18 '22 at 09:25
  • @AlanBirtles but specifically that may block the caller correct? So in the event of eg a slow server which slows down one of the websockets, writing to that websocket will halt the world until the write completes. How I would normally handle this with standard tcp sockets is use non-blocking mode, and when I get back `EWOULDBLOCK`, enqueue the data and carry on. When the socket becomes writeable again, complete the write. Since non-blocking is not supported in beast, what is the analogous approach? – Steve Lorimer May 18 '22 at 09:33
  • Just use the async calls – Alan Birtles May 18 '22 at 09:34
  • @AlanBirtles in the case of the async calls if I have additional slow processing to do *after* the attempt to write, such as logging etc, the write will only occur **after** I return control to the event loop. So what I'd *like* to do is attempt to write synchronously (which will work in 90% of the cases) so the data is sent, and then perform my slow tasks which would otherwise delay the write. In the 10% of cases where a write doesn't complete immediately, then an alternative async operation should be employed - but only in the fallback situation. Do you think it's possible? Any suggestions? – Steve Lorimer May 18 '22 at 09:38
  • It's certainty possible but sounds like a lot of work for little/no benefit over just using async – Alan Birtles May 18 '22 at 10:00
  • I don't recommend using boost synchronous writing operations - they suck for various reasons. Just use asynchronous write from the start and wait (if needed) until it's completed or failed - that's all. – ALX23z May 18 '22 at 10:22
  • @ALX23z please could you elaborate on the sync write op suckiness? – Steve Lorimer May 18 '22 at 10:26
  • Not sure if relevant to web socket. Had issues with typical tcp socket. For instance, synchronous operations tend to be non-cancellable. This problem eventually led me to completely rewrite the code a couple of times until it worked properly. – ALX23z May 18 '22 at 10:43

0 Answers0