Search code examples
c#.net-corewebsocketsystem.net.websockets

System.Net.WebSockets leaving sockets in close_wait after disconnect


I'm having issues closing a System.Net.WebSockets connection properly.

After some googling even found someone that explained how to do it properly, but his own samples leave the socket in close_wait.

I'll use that persons samples as his explanation was pretty good, the blogpost was here:

https://mcguirev10.com/2019/08/17/how-to-close-websocket-correctly.html

The samples on github here:

https://github.com/MV10/WebSocketExample

To reproduce, check out the git repo

Build the client and server app using System.Net.WebSockets:

dotnet build ./WebSocketExample/WebSocketExample.csproj
dotnet build ./WebSocketClient/WebSocketClient.csproj 

Run them:

./WebSocketExample/bin/Debug/netcoreapp3.0/WebSocketExample
./WebSocketClient/bin/Debug/netcoreapp3.1/WebSocketClient

I'm running this on linux, so watching for the sockets like this:

watch -n 2 'netstat -anp | grep ":8080" | grep "CLOSE_WAIT"'

Now, on the client, press ESC and a CLOSE_WAIT socket will show up.
This wouldn't be an issue if there were just a couple of connections, but when talking about hundreds/thousands we'll run into resource limitations.

I know that the close_wait means that the client connection has sent it's close (FIN) and it's now up to the server to clean up/close the socket.

What's wrong in this sample that the connections are not closed/cleaned up properly?


Edit:

Some additional info, tried an implementation of System.Net.WebSockets that I found on github and that one does seem to work as expected:

https://github.com/ninjasource/Ninja.WebSockets

I'd rather use the one in .net core, less code to maintain


Solution

  • Found a workaround for when using System.Net.WebSockets on the .net core github issue tracker.

    Discussed here: https://github.com/dotnet/runtime/issues/27469

    Solution seems to be:

    var context = listener.GetContext();
    var res = context.Response;
    res.StatusCode = 200;
    res.OutputStream.Write(buffer, 0, buffer.Length);
    res.OutputStream.Flush();
    res.OutputStream.Dispose();
    res.Close();    // the magic
    

    Says it's fixed, don't think it is fully fixed as currently running .net core 3.1 and without doing this a lot of sockets stay in close_wait for a while.