unosquare / embedio

A tiny, cross-platform, module based web server for .NET
http://unosquare.github.io/embedio
Other
1.45k stars 175 forks source link

WebSocket message won't be handled when sending too fast #556

Open nd1012 opened 2 years ago

nd1012 commented 2 years ago

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:

  1. Run an EmbedIO WebSocket server in one thread
  2. Connect using a ClientWebSocket in another thread on the same computer (I used a thread within the same process)
  3. Send a message to the server as soon as the ClientWebSocket.ConnectAsync method returned
  4. 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