Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abnormal closure of WebSocket does not return ReceiveAsync

Tags:

c#

websocket

I have a thread on the server for processing data received from a client over a WebSocket connection:

    public HttpResponseMessage Get()
    {
        if (HttpContext.Current.IsWebSocketRequest)
        {
            HttpContext.Current.AcceptWebSocketRequest(ProcessWebSocket);
        }

        return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
    }

    private async Task ProcessWebSocket(AspNetWebSocketContext context)
    {
        WebSocket webSocket = context.WebSocket;    //Gets the current WebSocket object. 
        const int maxMessageSize = 1024;
        byte[] receivedDataBuffer = new byte[maxMessageSize];
        logger.Debug("WSC-New WebSocket connection");
        while (webSocket.State == WebSocketState.Open)
        {
            var timeOut = new CancellationTokenSource(70000).Token;
            WebSocketReceiveResult webSocketReceiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(receivedDataBuffer), timeOut);
            //If input frame is cancelation frame, send close command. 
            if (webSocketReceiveResult.MessageType == WebSocketMessageType.Close)
            {
                await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, String.Empty, CancellationToken.None);
                logger.Debug("WSC-Close WebSocket connection frame received");
            }
            else
            {
                //Process received data....
            }
        }
        logger.Debug("WSC-WebSocket closed, WebSocket state: {0}", webSocket.State.ToString());
    }

As long as the other side closes the WebSocket connection correctly I get the logger message at the end that says the websocket was closed, which means this thread terminated correctly. If the client goes to sleep or the program stops abruptly then a normal WebSocket closure does not occur. In that case webSocket.ReceiveAsync never returns. I am worried that I might have a serious memory leak if enough of these threads are started but never terminated. The timeout cancellation token is supposed to make it return after 70 seconds but it does not happen. If I try to access the webSocket object from another thread in this situation I get the following exception: Cannot access a disposed object.

How can I get back from await webSocket.ReceiveAsync(new ArraySegment(receivedDataBuffer), timeOut); to close this thread properly?

like image 212
ControlYourWay Avatar asked Oct 18 '22 07:10

ControlYourWay


1 Answers

The Problem:

Closure of almost any connection abruptly will cause the other socket to never get anymore data and this leads to your socket being left open just like you said.

The Solution:

Try using Keep-Alive to decide when the connection times out, and another solution would be to use a separate thread that could be killed to drop it, however I am not sure how well that work for you.

Starting the socket EX:

Thread X = new Thread(() => {
    Connect();
});
X.Start();

Ending the socket EX:

X.Abort();
// You could also force a Garbage Collection using
GC.Collect();
like image 123
Sean Mitchell Avatar answered Oct 21 '22 03:10

Sean Mitchell