C++: Dealing with blocking (web)socket

Caporegime
Joined
18 Oct 2002
Posts
32,623
This has been killing me for a week :(

I have a C++ web-sockets server using Poco library.
The socket needs to be blocking for websockets but I set a fairly short timeout. The problem is the socket blocks on send, sometimes far longer than the specified timeout which is when things screw up.

This websocket server receives a UDP data feed that contains various events. An event listener class/lib listens to these events, and there is a subscriber mechanism with a function callback so when a certain event arrives in the data feed a method in the subscribing class is triggered passing on the data to the callback. The websocket should basically pass on the data from the listener/callback to the client.

The problem is if this callback doesn't return then the whole subscription/listener will hang (it just loops over all subscription callbacks). So when the send on socket blocks any other events coming through the data feed won't trigger the callback. When the send blocks for long the socket is closed, when the socket is closed my whole websocket handler is deleted and the callback function will thus never return.

To resolve this I tried making the callback spawn a new thread to do the sending so the callback always returns. The issue here is when the websocket handler gets deleted any thread that is blocked sending will crash the server because the socket has been deleted.

So how can I deal with a socket that sometimes blocks for far longer than the timeout?
 
Associate
Joined
9 Jun 2004
Posts
423
To resolve this I tried making the callback spawn a new thread to do the sending so the callback always returns. The issue here is when the websocket handler gets deleted any thread that is blocked sending will crash the server because the socket has been deleted.

Can you arrange the lifetime management such that this doesn't happen (e.g. using reference counting)?

The sender thread could hold a strong reference to something which keeps the socket alive (i guess either the socket itself or the owning handler).
 
Caporegime
OP
Joined
18 Oct 2002
Posts
32,623
Can you arrange the lifetime management such that this doesn't happen (e.g. using reference counting)?

The sender thread could hold a strong reference to something which keeps the socket alive (i guess either the socket itself or the owning handler).

I tried things like this by putting checks in the destructor so the socket wouldn't be closed but I ended up in a load of complex issues with the sending threads running indefinitely and eventually timeout out leading to a crash or simply using resources.


I think I made a bit of progress as one of the exception handlers was too narrowly focused (i.e. catching a sub-class) so when the socket would fail to send and would throw an exception I wasn't catching it. But the debug data was not at all helpful (gdb was just not returning any stack trace and the core dumps seemed meaningless).


I also reduced the timeout to a much smaller value so if a send thread is left the socket timeout will occur in a more reasonable time.

So far it is running fine but I am not at all convinced it is fixed since I spent 2 weeks working 10-11 hrs a day on this issue and nothing seemed to work until like magic 3 hrs ago it passed all my stress tests.

Part of the issue is undoubtedly I hate doing multi-threaded stuff and the debugging is immensely complex.
 
Associate
Joined
9 Jun 2004
Posts
423
If you've got to the destructor, it's really too late -- I mean something like

//main thread, server function
{
auto handler = std::make_shared<HandlerType> //owns sockets?

//do stuff. may cause send threads to spawn
}

send_thread(SocketType socket, std::shared_ptr<HandlerType> my_strong_ref)
{
//ref dropped when thread ends. handler always alive while
//a sending thread is alive. auto-deleted when last ref. drops.
}
 
Back
Top Bottom