embedio
embedio copied to clipboard
WebSocket message won't be handled when sending too fast
Describe the bug
I use the EmbedIO WebSocket module and the ClientWebSocket
in a local unit testing environment (server and client within the same process, everything runs asynchronous). When I use the ClientWebSocket
to connect to the server and send a message directly after the ConnectAsync
method returned, this message may not be processed by the EmbedIO WebSocket module.
To avoid this behavior, I had to change the protocol and send an empty message within the OnClientConnectedAsync
. When the client is waiting for this empty message and starts sending after it was received, the OnMessageReceivedAsync
at the server side is being executed as expected.
To Reproduce Steps to reproduce the behavior:
- Run an EmbedIO WebSocket server in one thread
- Connect using a
ClientWebSocket
in another thread on the same computer (I used a thread within the same process) - Send a message to the server as soon as the
ClientWebSocket.ConnectAsync
method returned - At the server side, the
OnMessageReceivedAsync
may not be executed for the first message(s)
Expected behavior
At the client side I (as a naive user) actually assume that after connected, the server is able to process sent messages. When I look into the source of the WebSocketModule
source, I find the connection process in the OnRequestAsync
method. This method accepts the WebSocket using AcceptWebSocketAsync
, then does tidy actions, then stores the context, then calls the OnClientConnectedAsync
method and finally runs the message processing loop. Between AcceptWebSocketAsync
and message loop processing is a time gap where no messages will be processed, which results in a timing problem, when a fast client starts sending messages directly after the WebSocket connection has been established successfully.
As I understand, the ProcessEmbedIOContext
was used as message loop processor in my case. In this method an OnMessage
event handler will be attached for processing received messages. This happens after the client was able to send messages already. If the AcceptWebSocketAsync
would be executed after the OnMessage
handler has been attached, the timing problem should be solved.
Anyway, the timing problem may not happen with slow clients (f.e. LAN or WAN connected peers). For all other cases, an empty message from the server could signal to the client that the server is ready for processing messages, after the connection has been established (as a workaround). The RFC says in the handshake sections, the server can start processing messages after confirming the OPEN state. If you stick to it, you're doing it right, and the timing problem is a part of the RFC. In this case the client should never be the peer that starts sending messages.
System environment
- Windows 10 64bit
- Visual Studio 2022
- MS Test Project (C#)
- EmbedIO NuGet version