4

我编写了许多通过 TCP 进行通信的小程序。我在系统挂起方面遇到了无穷无尽的问题,因为一个程序已关闭其网络连接,而另一个端点不知何故没有注意到它现在已断开连接。

我期待在已关闭的 TCP 连接上执行 I/O 以引发某种 I/O 异常,但程序似乎只是挂起,永远等待另一个端点回复。显然,如果连接关闭,则该回复永远不会到来。(如果您将其放置二十分钟,它甚至似乎都不会超时。)

有什么方法可以强制远程端“看到”我已经关闭了网络连接?

更新:这是一些代码...

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);
  }
}
4

3 回答 3

2

当应用程序以正确的方式关闭套接字时,它会发送一条包含 0 字节的消息。在某些情况下,您可能会收到SocketException指示出了问题。在第三种情况下,在双方之间没有任何通信的情况下,远程方不再连接(例如通过拔出网络电缆)。

如果最后一件事发生,您必须将数据写入套接字以检测您无法再访问远程方。这就是为什么发明了保持活动机制的原因——它们经常检查它们是否仍然可以与对方通信。

看到您现在发布的代码:在对其使用NetworkStream操作Read时,将返回一个值 0(字节),表示客户端已关闭连接。

文档提到了两者

“如果没有数据可供读取,Read 方法返回 0。”

“如果远程主机关闭连接,并且已接收到所有可用数据,则 Read 方法立即完成并返回零字节。”

在同一段中。实际上NetworkStream,如果在连接打开时没有数据可供读取,则会阻塞。

于 2013-09-17T10:09:43.450 回答
1

嗨数学兰花,

您可能会在此处找到您要查找的内容:

http://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html

那里有一些关于使用 TCP 套接字和检测半开连接的重要信息。

您也可以参考这篇似乎有相同解决方案的帖子:

TcpClient 与服务器通信以保持 C# 中的活动连接?

-戴夫

于 2013-09-17T10:21:07.637 回答
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。这是一个围绕套接字的包装器,它提供了连接状态检查工具。

于 2013-09-17T10:25:51.270 回答