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


78

关闭或重置TcpClient连接的正确方法是什么?我们拥有与硬件进行通信的软件,但是有时出了点问题,在重新启动软件之前,我们不再与之通信。

我尝试过强制TcpClient.Close()甚至将其设置为null,但这不起作用。仅完全重新启动软件即可。

有什么建议吗?


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

这是一个处理通讯的库。软件本身可以调用Controller类(代表硬件)的ResetConnection()方法。

目前看起来像

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

现在,从我在这里阅读的内容中,我应该使用tcpClient.Dispose()代替“ = null”

我将尝试一下,看看是否有所作为。

Answers:


93

您必须在关闭连接之前关闭流:

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

关闭客户端不会关闭流。


11
如果关闭TcpClient不会关闭连接,它到底会关闭什么?有什么理由要关闭TcpClient吗?
Qwertie 2011年

我真的不知道,您应该使用Reflector进行检查,但是它可能会关闭其他使用的对象而不是流(可能可以在不同对象之间共享该流,这就是为什么它不会自动关闭的原因,只是猜测)。
Ignacio Soler Garcia

36
请注意,仅在.NET 1.1及更早版本中存在导致必须关闭流的错误(support.microsoft.com/kb/821625)。我在.NET 4.5中测试了示例代码,并且无需在流上调用close即可正常工作。
2014年

4
如果我使用tcpClient.Close()而不是tcpClient.Client.Close()或tcpClient.GetStream()。Close(),在.NET 4.6.1上仍然会出现间歇性问题。前几天,我几乎迷失了方向,直到找到了。
Mike Marynowski '16

使用.NET Standard的System.Net.Sockets.TcpClient,请致电Dispose()。没有Close()办法。
NathanAldenSr

26

鉴于已接受的答案已经过时,而其他答案我都看不到,因此我正在创建一个新答案。在.Net 2和更早版本中,必须在关闭连接之前手动关闭流。该错误已TcpClient在C#的所有更高版本中修复,并且如Close方法的文档中所述,对该方法的调用会同时Close关闭连接和流

根据Microsoft Docs编辑

Close方法将实例标记为已处置,并请求关联的Socket关闭TCP连接。基于LingerState属性,当仍有数据要发送时,在调用Close方法之后,TCP连接可能会保持打开状态一段时间。基础连接完成关闭时不提供任何通知。

调用此方法最终将导致关联的Socket关闭,并且还将关闭关联的NetworkStream(如果已创建),该NetworkStream用于发送和接收数据。


@Twometer您定位的是哪个版本的.Net?
约翰·德米特里

它是.NET 4.6.1
Twometer '18

我正在调用TcpClient.Close(),tcpClient.Client.Close()、. Disconnect()之类的东西,但它不会关闭。仅当我
终止

您链接的文章中的示例仍然在调用networkStream.Close();之前调用tcpClient.Close();,因此该示例已过期,或者您仍然必须手动关闭基础流。
Deantwo

@Deantwo更新了我的答案。它标记它已准备好处置。虽然不能保证何时将其处置。
约翰·德米特里

22

使用字词:using。有良好的编程习惯。

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

42
不适用于所有型号。如果您在一个代码块中临时使用连接,但是如果您有一个客户端实现想要将连接保持为成员,则此方法将失败,这很好。您还会发现,根据类文档,在TcpClient上调用Dispose()不会关闭基础套接字。使用只会处理。
Gusdor

1
这在异步和非blockign套接字中是行不通的,如果您想将连接存储在某个地方并对其进行管理,则实际上不能使用此代码。
卡斯(Kas)

7
@Gusdor查看反射源,似乎Dispose(true)会在客户端上调用Close()。(.NET 4.0)
dtroy

必须是新添加的。我张贴参考.net 3.5。发现得好!
Gusdor

1
@ Dermot,@ SteveJobs很好,既然将来在这里有async关键字,它就会;-)。如果您在块内调用,它甚至可以与BeginConnect()和兼容……EndConnect()End…using
binki 2015年

8

尽管拥有所有适当的using语句,但调用Close,具有一些指数退避逻辑并重新创建TcpClientI,我仍然看到问题,即如果不重新启动应用程序,应用程序将无法恢复TCP连接。它不断失败 System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host

但是,有一个选项LingerStateTcpClient出现可能已经解决了这个问题(可能不知道几个月我自己的硬件设置不仅不能对经常!)。参见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 })
   ...

嗨!我有完全相同的问题,尽管有时所有适当的代码有时都会在随机时间出现此异常,但LingerOption解决了您的问题吗?我正在认真考虑将我的所有代码迁移到UDP,以摆脱此间歇性问题
Rafael

@rafael我认为它已经解决了我的问题:自发布此消息以来我再也没有看到此问题。
伊恩·默瑟

6

关闭套接字连接并允许重新使用套接字:

tcpClient.Client.Disconnect(false);

1
我很困惑为什么以后要重新打开连接时需要这样做。简单地关闭流并关闭TcpClient然后会在稍后引发异常.Connect
pep 2015年

6
您不是说Disconnect(true)吗?
WDUK

6

关闭套接字以便重新打开的正确方法是:

tcpClient.Client.Disconnect(true);

Boolean参数指示是否要重用套接字:

断开方法的使用


5

除某些内部日志记录外,关闭==处理。

处置调用tcpClient.Client.Shutdown(SocketShutdown.Both),但是它会占用任何错误。也许如果直接调用它,可以获得一些有用的异常信息。


1

您是否尝试过显式调用TcpClient.Dispose()

并且您确定您具有TcpClient.Close()和TcpClient.Dispose()-ed所有连接吗?


只有一个连接,我关闭了它,但没有处置它……有什么区别吗?(我想是的,只是问了:-)
TimothyP,2009年

TcpClient.Dispose受保护,不能直接调用。
他们

@theycallmemorty doc则相反。msdn.microsoft.com/en-us/library/vstudio/...
chakrit

2
这是一个显式的接口实现。因此,在将TcpClient强制转换为IDisposable之前,他是不可见的,即((IDisposable)client).Dispose()
Joseph Lennox
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.