86

What is the correct way to close or reset a TcpClient connection? We have software that communicates with hardware but sometimes something goes wrong and we are no longer to communicate with it, until we restart the software.

I have tried forcing TcpClient.Close() and even setting it to null but that doesn't work. Only a complete restart of the software works.

Suggestions?


I can't use the using keyword because TpcClient is only defined in one location, but used throughout the library. (And there is only one connection at any given time)

It's a library that handles communication. The software itself can call the ResetConnection() method of the Controller class (which represents the hardware).

It currently looks like

if (tcpClient != null)
{
    tcpClient.Close();
    tcpClient = null;
}

Now from what I've read here I should use tcpClient.Dispose() instead of " = null"

I'll give that a try and see if it makes a difference.

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
TimothyP
  • 21,178
  • 26
  • 94
  • 142

9 Answers9

100

You have to close the stream before closing the connection:

tcpClient.GetStream().Close();
tcpClient.Close();

Closing the client does not close the stream.

Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207
  • 14
    If closing the TcpClient doesn't close the connection, what the hell does it close? Is there any reason to close the TcpClient? – Qwertie Mar 22 '11 at 15:20
  • I really don't know, you should check with Reflector, but it probably closes other objects used rather than the stream (maybe the stream can be shared between different objects and that's why its not automatically closed, just guessing). – Ignacio Soler Garcia Mar 22 '11 at 16:39
  • 44
    Note that bug ([support.microsoft.com/kb/821625](http://support.microsoft.com/kb/821625)) that made it necessary to close the stream only exists in .NET 1.1 and earlier. I tested out the sample code in .NET 4.5, and it works fine without calling close on the stream. – Anssssss Jan 02 '14 at 15:56
  • 5
    I still get intermittent problems on .NET 4.6.1 if I use tcpClient.Close() instead of tcpClient.Client.Close() or tcpClient.GetStream().Close(). I almost lost my mind the other day until I found this. – Mike Marynowski Jul 01 '16 at 10:24
  • With .NET Standard's `System.Net.Sockets.TcpClient`, call `Dispose()`. There is no `Close()` method. – NathanAldenSr Apr 04 '17 at 21:53
  • @NathanAldenSr: not true as far as I know: https://msdn.microsoft.com/es-es/library/system.net.sockets.tcpclient.close(v=vs.110).aspx – Ignacio Soler Garcia Apr 05 '17 at 06:55
  • @IgnacioSolerGarcia I think `TcpClient`'s interface may be changing over time. `TcpClient` in my .NET Core console application targeting `netcoreapp1.1` does not expose a `Close()` method, but `TCPClient.cs` from the `dotnet/corefx` repo does: https://github.com/dotnet/corefx/blob/master/src/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs. Strange... – NathanAldenSr Apr 05 '17 at 15:21
  • @NathanAldenSr: .Net Core is different from .Net Framework. As it is a subset of the main Framework methods may be missing. – Ignacio Soler Garcia Apr 06 '17 at 07:35
  • The stream is disposed in .NET 4 and newer, for code inspection: http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/Net/System/Net/Sockets/TCPClient@cs/1305376/TCPClient@cs – Franki1986 Oct 23 '17 at 06:15
31

Given that the accepted answer is outdated and I see nothing in the other answers regarding this I am creating a new one. In .Net 2, and earlier, you had to manually close the stream before closing the connection. That bug is fixed in all later versions of TcpClient in C# and as stated in the doc of the Close method a call to the method Close closes both the connection and the stream

EDIT according to Microsoft Docs

The Close method marks the instance as disposed and requests that the associated Socket close the TCP connection. Based on the LingerState property, the TCP connection may stay open for some time after the Close method is called when data remains to be sent. There is no notification provided when the underlying connection has completed closing.

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.

John Demetriou
  • 4,093
  • 6
  • 52
  • 88
  • @Twometer which version of .Net are you targeting? – John Demetriou Nov 05 '18 at 08:57
  • it's .NET 4.6.1 – Twometer Nov 05 '18 at 08:59
  • I am calling TcpClient.Close(), tcpClient.Client.Close(), .Disconnect() whatever and it doesn't close. Only when I kill the process, the server says "Connection closed" – Twometer Nov 05 '18 at 09:00
  • The example in the article you linked still calls `networkStream.Close();` before calling `tcpClient.Close();`, so either the example is out of date or you still have to manually close the underlying stream. – Deantwo Nov 05 '18 at 13:42
  • @Deantwo Updated my answer. It marks it as ready to be disposed. No guarantee on when it will be disposed though. – John Demetriou Nov 06 '18 at 09:50
  • @Twometer Updated my answer. It marks it as ready to be disposed. No guarantee on when it will be disposed though. – John Demetriou Nov 06 '18 at 09:50
22

Use word: using. A good habit of programming.

using (TcpClient tcpClient = new TcpClient())
{
     //operations
     tcpClient.Close();
}
Rob
  • 47,999
  • 5
  • 74
  • 91
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
  • 48
    Not applicable in all models. This is great if you are using the connection temporarily within one code block but if you have a client implementation that wants to maintain a connection as a member, this method will fail. You will also find that, as per the class documentation, calling Dispose() on the TcpClient does not close the underlying socket. Using will only dispose. – Gusdor Nov 18 '11 at 16:30
  • 1
    This is not gonna work in async and non-blockign sockets, And actully this code can not be used if you want to store the connection somewhere and manage it. – Kas Jul 09 '13 at 07:06
  • 7
    @Gusdor Looking at the reflected source, it does seem that Dispose(true) will call Close() on the client. (.NET 4.0) – dtroy Aug 13 '13 at 01:47
  • Must be a new addition. I posted in reference to .net 3.5. Well spotted! – Gusdor Aug 13 '13 at 06:58
  • 1
    @Dermot, @SteveJobs well, now that the future is here with the `async` keyword, it does ;-). It would even be compatible with `BeginConnect()` and `EndConnect()`, provided you call `End…` inside the `using` block… – binki Nov 27 '15 at 15:38
12

Despite having all the appropriate using statements, calling Close, having some exponential back off logic and recreating the TcpClient I've still been seeing issues where the application cannot recover the TCP connection without an application restart. It keeps failing with a System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

But there is an option LingerState on the TcpClient that appears it may have solved the issue (might not know for a few months as my own hardware setup only fails about that often!). See MSDN.

// This discards any pending data and Winsock resets the connection.
LingerOption lingerOption = new LingerOption(true, 0);

using (var tcpClient = new TcpClient 
       {SendTimeout = 2000, ReceiveTimeout = 2000, LingerState = lingerOption })
   ...
Ian Mercer
  • 38,490
  • 8
  • 97
  • 133
  • Hi! I have exactly the same problem, despite having all the appropiate code sometimes this exception appears at random times, the LingerOption solved your issue? I'm thinking seriously to migrate all my code to UDP just to get rid of this intermittent problem – Rafael May 21 '19 at 17:59
  • @rafael I think it has solved my problem: I have not seen this issue at all since posting this. – Ian Mercer May 22 '19 at 02:12
8

The correct way to close the socket so you can re-open is:

tcpClient.Client.Disconnect(true);

The Boolean parameter indicates if you want to reuse the socket:

Disconnect method usage

Draken
  • 3,134
  • 13
  • 34
  • 54
Kevin Gigiano
  • 101
  • 1
  • 1
8

Except for some internal logging, Close == Dispose.

Dispose calls tcpClient.Client.Shutdown( SocketShutdown.Both ), but its eats any errors. Maybe if you call it directly, you can get some useful exception information.

jyoung
  • 5,071
  • 4
  • 30
  • 47
7

Closes a socket connection and allows for re-use of the socket:

tcpClient.Client.Disconnect(false);
Justin Tanner
  • 14,062
  • 17
  • 82
  • 103
  • 1
    I am confused about why I need to do this if I want to later re-open the connection. Simply closing streams & closing the `TcpClient` then throws an exception on a later `.Connect`. – p e p Jun 10 '15 at 13:37
  • 6
    Don't you mean Disconnect(true) ? – WDUK Dec 12 '17 at 03:54
  • 1
    @WDUK I thought so too, but if you use `disconnect(true)` the socket can hang waiting to be reused..... it's easier to set to false then make another socket another time. – rupweb Mar 08 '22 at 16:56
  • Good to know, thanks! – WDUK Mar 11 '22 at 07:55
2
client.Dispose();
client.Close();
 if (stream != null)
    {
      clientstream.Dispose();
      clientstream.Close();
     }
payam purchi
  • 226
  • 1
  • 11
1

Have you tried calling TcpClient.Dispose() explicitly?

And are you sure that you have TcpClient.Close() and TcpClient.Dispose()-ed ALL connections?

chakrit
  • 61,017
  • 25
  • 133
  • 162
  • There is only one connection, and I closed it but I did not dispose it... does that make a difference? (I suppose it does, just asking :-) – TimothyP Jan 08 '09 at 18:32
  • TcpClient.Dispose is protected and cannot be called directly. – theycallmemorty Oct 21 '14 at 19:55
  • @theycallmemorty doc says otherwise. http://msdn.microsoft.com/en-us/library/vstudio/bb340916(v=vs.100).aspx – chakrit Oct 22 '14 at 06:44
  • 2
    It's an explicit interface implementation. So it's not visible tot he type TcpClient until it's cast to IDisposable, ie, `((IDisposable)client).Dispose()` – Joseph Lennox Mar 11 '15 at 17:04