Search code examples
c#asyncsockettcplistenertcpdisconnection

Why would TcpListener be leaking ESTABLISHED connections?


I have an application that's listening messages from a modem in some 30 cars. I've used TcpListener to implement server code that looks like this (error handling elided):

...
listener.Start()
...
void 
BeginAcceptTcpClient()
{
    if(listener.Server.IsBound) {
        listener.BeginAcceptTcpClient(TcpClientAccepted, null);
    }
}

void 
TcpClientAccepted(IAsyncResult ar)
{
    var buffer = new byte[bufferSize];

    BeginAcceptTcpClient();
    using(var client = EndAcceptTcpClient(ar)) {
    using(var stream = client.GetStream()) {
        var count   = 0;
        while((count = stream.Read(buffer, total, bufferSize - total)) > 0) {
            total += count;
        }
    }
    DoSomething(buffer)
}

I get the messages correctly, my problem lies with disconnections. Every 12 hours the modems get reset and get a new IP address, but the Server continues to hold the old connections active (they are marked as ESTABLISHED in tcpview). Is there any way to set a timeout for the old connections? I thought that by closing the TcpClient the TCP connection was closed (and that's what happens in my local tests), what I'm doing wrong?


Solution

  • I'm actually a little confused by the code sample - the question suggests that these questions are open a reasonably long time, but the code is more typical for very short bursts; for a long-running connection, I would expect to see one of the async APIs here, not the sync API.

    Sockets that die without trace are very common, especially when distributed with a number of intermediate devices that would all need to spot the shutdown. Wireless networks in particular sometimes try to keep sockets artificially alive, since it is pretty common to briefly lose a wireless connection, as the devices don't want that to kill every connection every time.

    As such, it is pretty common to implement some kind of heartbeat on connections, so that you can keep track of who is still really alive.

    As an example - I have a websocket server here, which in theory handles both graceful shutdowns (via a particular sequence that indicates closure), and ungraceful socket closure (unexpectedly terminating the connection) - but of the 19k connections I've seen in the last hour or so, 70 have died without hitting either of those. So instead, I track activity against a (slow) heartbeat, and kill them if they fail to respond after too long.

    Re timeout; you can try the ReceiveTimeout, but that will only help you if you aren't usually expecting big gaps in traffic.