我写了很多通过TCP进行通信的小程序。由于一个程序已关闭其网络连接,而另一个端点无法注意它现在已断开连接,我在系统挂起时遇到了无数问题。
我期待在已关闭的TCP连接上进行I / O以抛出某种I / O异常,但是程序似乎只是挂起,等待另一端的永远点回复。显然,如果连接已关闭,则该回复永远不会到来。 (如果你把它留下来,比如20分钟,它似乎没有超时。)
是否有某种方法可以强制远程端“看到”我已关闭网络连接?
更新:以下是一些代码......
public sealed class Client
{
public void Connect(IPAddress target)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ipAddress, 1177);
_stream = new NetworkStream(socket);
}
public void Disconnect()
{
_stream.Close();
}
}
public sealed class Server
{
public void Listen()
{
var listener = new TcpListener(IPAddress.Any, 1177);
listener.Start();
var socket = listener.AcceptSocket();
_stream = new NetworkStream(socket);
...
}
public void Disconnect()
{
socket.Shutdown(SocketShutdown.Both);
socket.Disconnect(false);
}
}
答案 0 :(得分:2)
当应用程序以正确的方式关闭套接字时,它会发送包含0个字节的消息。在某些情况下,您可能会收到SocketException
表示出现问题。在第三种情况下,远程方不再连接(例如通过拔出网络电缆)而没有双方之间的任何通信。
如果最后发生这种情况,您必须将数据写入套接字,以便检测到您无法再访问远程方。这就是发明保持活动机制的原因 - 它们经常检查它们是否仍能与另一方进行通信。
查看您现在发布的代码:使用NetworkStream
时,Read
操作会返回0(字节)值,表示客户端已关闭连接。
“如果没有可用于读取的数据,则Read方法返回0.”
和
“如果远程主机关闭连接,并且已收到所有可用数据,则Read方法立即完成并返回零字节。”
在同一段中。实际上NetworkStream
会阻止在连接打开时没有可用于读取的数据。
答案 1 :(得分:1)
Hi MathematicalOrchid,
您可以在这里找到您要找的内容:
http://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html
在处理TCP套接字和检测半开连接时,有一些很好的信息。
你也可以参考这篇似乎有相同解决方案的帖子:
TcpClient communication with server to keep alive connection in c#?
-Dave
答案 2 :(得分:1)
您正在打开套接字,并将其分配给流。在此过程结束时,您将关闭网络流,但不关闭套接字。
要使NetworkStream.Close()
关闭底层套接字,必须在构造函数中将所有权参数设置为true - 请参阅http://msdn.microsoft.com/en-us/library/te7e60bx.aspx上的MSDN文档。
这可能会导致连接挂起,因为底层套接字未正确关闭。
更改
_stream = new NetworkStream(socket);
要
_stream = new NetworkStream(socket, true);
另外,如果您的小应用不需要最高性能,则应尝试使用TCPClient
代替http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient%28v=vs.100%29.aspx。这是套接字的包装器,它提供连接状态检查功能。