FireCatMagic
FireCatMagic

Reputation: 1

Awaiting ClientWebSocket.RecieveAsync in .net never returns again after returning only once

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

I have a thread that will poll this ClientWebSocket repeatedly by calling a function.

poll_thread = new Thread(poll);
poll_thread.Start();

The poll functions looks as follows:

        private async void poll() {
            while (true) { 
                // Wait 16 ms (1/60 of a second) before making another polling attempt.
                Thread.Sleep(16);

                switch (web_socket.State) {
                    case WebSocketState.Open: {
                        if (socket_connected == false) { socket_connected = true; }
                        try { 
                            // RecieveAsync automatically polls and recieves 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 recieved, 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;
                }
            }
        }

It's supposed to keep repeatedly polling the websocket. The console output As shown by the console output, after the first time it receives data, and attempts to poll again, the ValueWebSocketReceiveResult result = await web_socket.ReceiveAsync(memory, CancellationToken.None); never actually finishes awaiting.

If the program is left running, eventually it raises an exception on that line that reads
System.Net.WebSockets.WebSocketException: 'The remote party closed the WebSocket connection without completing the close handshake.'

I do not understand why my implementation does not work, as it is a implementation ported from Godot Engine's WebSocketPeer The GDScript implementation looks similar to the C# implementation.

func poll() -> void:
    socket.poll()
    match socket.get_ready_state():
        WebSocketPeer.STATE_OPEN:
            while socket.get_available_packet_count():
                if not socket_connected:
                    socket_connected = true
                    call(&"emit_signal", &"connection_established")
                
                var packet: PackedByteArray = socket.get_packet()
                print(packet.size())
                handle_event(packet)
        WebSocketPeer.STATE_CLOSING:
            # Keep polling to achieve proper close.
            return
        WebSocketPeer.STATE_CLOSED:
            socket_connected = false
            call(&"emit_signal", &"connection_closed", socket.get_close_code())

This version works perfectly as intended, it receives all of the packets of information as it should, connecting with the same configuration, but the point of this project is to not use the Godot Engine inside it, so this is one thing being ported.

Upvotes: 0

Views: 66

Answers (1)

joana
joana

Reputation: 73

Handling for WebSocketState.CloseSent and WebSocketState.CloseReceived occurs during the closing process of a WebSocket connection. To ensure that the WebSocket is fully closed, you should keep polling until the WebSocket reaches the Closed state. Use ClientWebSocket.CloseOutputAsync instead of CloseAsync to indicate that no more output will be sent from the client. This graceful approach allows you to respond appropriately to the WebSocket close event and ensure proper closure of the connection.

Upvotes: 1

Related Questions