FireCatMagic
FireCatMagic

Reputation: 1

Awaiting ClientWebSocket.ReceiveAsync only receives one packet of information, and then all other awaits never return

I'm using the System.Net.WebSockets.ClientWebSocket class in C# on .NET 6.0.

I have a timer set up that repeatedly will poll the websocket for connections, shown here. The timer is elapsed every 16 ms.

When the packet is received, it'll deserialize it as JSON and create an event. This works, but it only does it once.

I added the print lines for testing:

Console.WriteLine("Awaiting started") 

and

Console.WriteLine("Awaiting ended")

Awaiting started should be printed when the websocket is polled. It should print "Awaiting ended" after the websocket has finished the polling, and then if the packet received isn't empty, it'll deserialize it.

private async void poll(Object? sender, ElapsedEventArgs event_args) 
{
    switch (web_socket.State) 
    {
        case WebSocketState.Open: 
            {
                if (socket_connected == false) 
                {
                    socket_connected = true;
                }

                try 
                {
                    // ReceiveAsync automatically polls and receives the packet.
                    Memory<Byte> memory = new Memory<Byte>(new Byte[1024]);
                    Console.WriteLine("Awaiting started");
                    ValueWebSocketReceiveResult result = await web_socket.ReceiveAsync(memory, CancellationToken.None);
                    Console.WriteLine("Awaiting ended");

                    // Only attempt deserialization if a packet was received, aka the buffer is not empty.
                    if (result.Count != 0) 
                    {
                        deserialize_event(memory.Slice(0, result.Count).ToArray());
                    }
                } 
                catch (Exception exception) 
                { 
                    Console.WriteLine("Pusher polling error: " + exception.ToString());
                }
            } 
            break;

        case WebSocketState.Closed: 
            {
                connection_closed(web_socket.CloseStatus);
            } 
            break;
    }
}

What's supposed to happen: it should first print that its awaiting, then await the packet, then write the contents to the buffer, then move on with the execution, printing that the Await ended.

What actually happens:

It only prints "Awaiting Ended" one singular time

It looks like it only receives one singular packet, and then all calls to ReceiveAsync never finish.

Upvotes: 0

Views: 153

Answers (1)

David Browne - Microsoft
David Browne - Microsoft

Reputation: 89090

Using a timer will call ReceiveAsync again before the previous call is complete, which is not supported.

Exactly one send and one receive is supported on each ClientWebSocket object in parallel. Issuing multiple sends or multiple receives at the same time (for example, without awaiting, or from multiple threads without synchronization) is not supported and will result in an undefined behavior.

https://learn.microsoft.com/en-us/dotnet/api/system.net.websockets.clientwebsocket?view=net-8.0

Instead of invoking the read from a timer, create a thread (or Long Lived Task), and invoke await websocket.ReceiveAsync in a loop.

Upvotes: 1

Related Questions