views:

475

answers:

3

I have a TcpClient object which sends some data to server, using its underlying NetworkStream.Write(). Therefor, I have:

TcpClient server = new TcpClient(serverName, 50001);

/* ... */

NetworkStream stream = server.GetStream();

Now, when a button is pressed, the connection should close. What is the right way to close the connection? The MSDN docs say that closing the TcpClient (with .Close()) does not in fact close the socket, only the TcpClient resources (that's at least the way I understood the docs).

So, would doing the next code correctly close the connection?

stream.Close();
server.Close();

Is this enough, or should I first check (somehow) if the stream (or server) can be closed (in case the connection is half-open or something)...

Even more, NetworkStream.Close() MSDN docs states that it releases resources (even sockets), so maybe closing the stream would be enough, taken that I prevent using the TcpClient after that point.

What is the right approach?

+2  A: 

As the docs say:

Calling this method will eventually result in the close of the associated Socket and will also close the associated NetworkStream that is used to send and receive data if one was created.

So server.Close(); will be enough.

Closing the NetworkStream first will never hurt though.

By the way, if you happen to be using the TcpClient only in one method, wrap it in a using( ) statement so that you're sure Dispose() (equivalent to Close()) is called on it, even if exceptions are thrown etc.

Joren
I guess I trusted IntelliSense too much. The popup for the TcpClient.Close() states this: "Disposes this System.Net.Sockets.TcpClient instance without closing the underlying connection." Strange thing. Thanks for the reply though.
kornelijepetak
Indeed, that's what the 3.0 docs (http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.close(VS.85).aspx) say in the first sentence ... but then the third sentence says that it *does* close the Socket and NetworkStream. The 3.5 docs (which I linked earlier) are consistent. I suspect the line in the 3.0 docs was a mistake.
Joren
A: 

You're right in closing the stream then the server. This should result in all sockets being closed successfully over time, as the documentation states. However, several head scratching bugs have taught me the important lesson over time:

Don't forget to flush!

stream.Flush();
stream.Close();
server.Close();

You will often lose some data you thought you might have sent otherwise. This also helps ensure that the stream should be empty and inactive when you close it.

Smallgods
From the docs on NetworkStream: "The Flush method implements the Stream.Flush method; however, because NetworkStream is not buffered, it has no affect on network streams. Calling the Flush method does not throw an exception."So it doesn't really matter if you flush the stream or not.
Joren
A: 

I will associate a TCP connection with a socket.

Generally, the procedure is like this: 1. Finish sending data 2. Call Socket.Shutdown with SocketShutdown.Send parameter 3. Loop on Receive until it returns 0 or fails with an exception 4. Call Close()

Here's a small sample in pseudo code that is very similar to C# :)

void CloseConnection(Socket socket)
{
   socket.Send(/*last data of the connection*/);
   socket.Shutdown(SocketShutdown.Send);

   try
   {
      int read = 0;
      while( (read = socket.Receive(/*application data buffers*/)) > 0 )
      {}
   }
   catch
   {
      //ignore
   }
   socket.Close();
}

If first and third steps are skipped - data loss can happen.

Taken from How to close TCP socket

Vadmyst