【问题标题】:Detect closed network connection检测关闭的网络连接
【发布时间】:2013-09-17 18:33:22
【问题描述】:

我编写了许多通过 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);
  }
}

【问题讨论】:

  • 在 TCP 中,进程通常不能永远挂起... TCP 发送 alive? 信号以检查其他节点是否仍然处于活动状态。
  • ...因此我很困惑。
  • 你考虑过TcpClient.LingerState吗?你如何使用 TCP? Socket 编程还是一些专门的库?
  • 有一个循环,您在程序内部接收数据的地方似乎挂起。发布该代码。

标签: c# tcp


【解决方案1】:

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

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

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

documentation 提到了两者

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

和

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

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

【讨论】:

  • 你的意思是Read() 返回零字节而不是抛出异常?哦,亲爱的...
  • @MathematicalOrchid 完全正确
  • 所以大概ReadByte() 也将返回-1 而不是抛出一个实际的异常......
  • @MathematicalOrchid 他们必须选择异常以外的其他东西,因为正确关闭的套接字不是例外情况;并且默认的 ReadByte 实现在后台调用 Read。
  • 我希望不必为此在代码中乱扔几十个相同的检查。 (这就是发明异常处理的原因......)哦,好吧,我想他们以这种方式设计它不是你的错。 :-(
【解决方案2】:

你好数学兰花,

您可能会在这里找到您想要的东西:

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

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

你也可以参考这个帖子,好像有同样的解决办法:

TcpClient communication with server to keep alive connection in c#?

-戴夫

【讨论】:

  • 这很有趣,但它似乎是在谈论进程何时死亡,或者网络链接出现故障。我正在尝试明确在一端关闭连接,这应该通知另一端,您会认为...
【解决方案3】:

您正在打开套接字,并将其分配给流。在进程结束时,您关闭网络流,但不关闭套接字。

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。这是对套接字的封装,它提供了连接状态检查工具。

【讨论】:

  • 如果我将流包装在 StreamReader 或 StreamWriter 对象中,是否需要类似的步骤?
  • @MathematicalOrchid StreamReader/StreamWriter 没有套接字构造函数,因此您必须将它们包裹在 NetworkStream 周围。这仍然会导致上述情况。此外,StreamReader 将阻塞,直到它接收到数据 - 如果没有数据(连接丢失或其他情况),那么您可能会遇到超时或无限期挂起。您最好的选择可能是使用/实施某种保持活动状态。
猜你喜欢
  • 2012-02-17
  • 2015-02-27
  • 2010-10-10
  • 2012-09-23
  • 2020-04-19
  • 2020-04-14
  • 2015-10-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多