Search code examples
c#.nettcpclient

Still able to retrieve Stream from TCPClient after remote client has called Dispose()


I have a simple client / server project, both running on my local machine.

In my client project, I am able to run the following (simplified) test code:

using(var tcpClient = new System.Net.Sockets.TCPClient())
{
  tcpClient.ConnectAsync(host, port).Wait(Timespan.FromSeconds(3));
  using (NetworkStream ns = tcpClient.GetStream())
  {
    ns.Write("Hello World", 0, "Hello World".Length);
    Thread.Sleep(100);
  }
}

This should write "Hello World" to the stream, then dispose everything after ~100ms, therefore making it unreadable after this point.

The problem is, the TcpListener running in my server project, is able to do roughly the following:

TcpClient client = TcpListener.AcceptTcpClient();
Thread.Sleep(750);
var stream = client.GetStream();  //I am still able to read the contents of this - shouldnt it be closed?

Could this be a problem caused by running the client/server on the same machine? Or do I have a fundamental misunderstanding of the Dispose() calls made on the client.


Solution

  • do I have a fundamental misunderstanding of the Dispose() calls made on the client.

    You certainly seem to.

    Disposing a TcpClient() for which GetStream() has been called disposes that local NetworkStream. In turn, disposing that stream calls Shutdown() on the underlying socket, and then closes the socket, freeing the native handle for it. (The latter two actions are taken in TcpClient, if no stream has been created yet. I.e. they will always happen regardless.)

    That's all. Nothing else.

    If you have sent data on the socket (and you have), and then waited long enough for that data to be transmitted (and you have), then the data is no longer in your control. And in fact, conceptually it's no longer under your control the moment you hand it to the socket. Even if in some cases you're able to get rid of the socket fast enough to prevent data from being sent, you shouldn't count on this. And in practice, the network drivers generally work very hard to transmit any data they've been given, no matter what happens on the local socket side.

    So, yes. If you expect that closing the local socket after you've already sent data is somehow going to affect whether the remote endpoint is able to receive the data that you've already sent, you do in fact have a fundamental misunderstanding of the Dispose() calls made on the client (the local socket).