如何正确和完全关闭/重置 TcpClient 连接?

关闭或重置 TcpClient 连接的正确方法是什么? 我们有与硬件通信的软件,但有时也有一些东西 如果出了问题,我们就不能再和它交流了,直到我们重新启动软件。

我尝试过强制 TcpClient.Close () ,甚至将其设置为 null,但这不起作用。 只有完全重启软件才能工作。

有什么建议吗?


我不能使用 using 关键字,因为 TpcClient 只在一个位置定义,而是在整个库中使用。(任何时候只有一个连接)

这是一个处理交流的图书馆。软件本身可以调用 Controller 类(代表硬件)的 ResetConnection ()方法。

目前看来

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

现在,根据我在这里读到的内容,我应该使用 tcpClient

我会试试看,看是否有用。

129234 次浏览

Have you tried calling TcpClient.Dispose() explicitly?

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

Use word: using. A good habit of programming.

using (TcpClient tcpClient = new TcpClient())
{
//operations
tcpClient.Close();
}

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.

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

tcpClient.Client.Disconnect(false);

You have to close the stream before closing the connection:

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

Closing the client does not close the stream.

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.

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

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 })
...
client.Dispose();
client.Close();
if (stream != null)
{
clientstream.Dispose();
clientstream.Close();
}