rbeeli / websocketclient-cpp

A transport-agnostic, high-performance, header-only C++23 WebSocket client library with minimal dependencies.
MIT License
1 stars 1 forks source link

Canceling synchronous read calls #5

Closed MeanSquaredError closed 2 months ago

MeanSquaredError commented 2 months ago

Hi,

Ideally there would be some way to cancel the synchronous reads, e.g. by passing a std::stop_token to the read method and then requesting a stop on the corresponding std::stop_source object.

I don't think that it can be implemented easily, because there is no easy way to poll simultaneously on a socket and a C++ synchronization primitive like conditional variable, semaphore, etc.

One workaround would be to open a pair of TCP sockets and connect them. Let's call these socket CANCEL sockets. The poll operation would block on two sockets, the WS socket and one of the CANCEL sockets. When we decide to cancel the WS read which blocks on the poll, we would send 1 byte through the other (non-polled) CANCEL socket, the poll would return and the read function would check if a cancellation is requested.

Another workaround could be implemented if there is a way to do websocket reads with a timeout. Then the caller could just call in loop the socket read function with a short timeout (e.g. 100ms) and betwen the calls if cancellation has been requested.

rbeeli commented 2 months ago

Hi,

Since the client implementation does no synchronization and isn't thread-aware, that's something the user needs to handle.

As you mentioned, I think the best solution is to have proper timeout support, then cancellation (with some delay) can be easily implemented by the user. I think pure cancellation for a websocket client is rarely needed.

With the async (i.e. ASIO) client, that's already possible, see https://github.com/rbeeli/websocketclient-cpp/blob/main/examples/ex_reconnect_asio.cpp#L99

For bare TCP (unencrypted) socket, I have extended the POSIX socket wrapper to be able to set read/write timeouts: https://github.com/rbeeli/websocketclient-cpp/blob/main/examples/ex_hello_ws.cpp#L43

Only for the built-in synchronous OpenSslSocket (WSS) case there is currently no timeout example, which is something to look into, e.g. via poll/select.

For most use-cases, I would recommend the async client based on coroutines and ASIO, as it provides a mature, and flexible network programming model.

MeanSquaredError commented 2 months ago

OK, I guess cancellation of synchronous/blocking calls is not feasible. On the other hand it is not as important as having read/write timeouts.