【问题标题】:How to efficiently determine the status of a socket in C#?如何在 C# 中有效地确定套接字的状态?
【发布时间】:2019-11-19 16:32:47
【问题描述】:

我有一个从客户端接收数据的服务器,我希望能够确定套接字是否仍然连接。

我正在使用以下函数来确定状态(source):

bool SocketConnected(Socket s)
{
    bool part1 = s.Poll(1000, SelectMode.SelectRead);
    bool part2 = (s.Available == 0);
    if (part1 && part2)
        return false;
    else
        return true;
}

但是,当 RTT(服务器/客户端之间)很高(~300 毫秒)并且变化(+- 60 毫秒)时,我的应用程序“崩溃”。从调试中我发现这是由于套接字被标识为未连接(SocketConnected()返回false)。不过我知道,套接字仍处于连接状态,因为我可以看到客户端流式传输从服务器请求的内容,并且服务器接收 Wireshark 捕获的数据。

我应该增加 Poll 的时间(但我不想阻止其他操作)还是将 Socket.Connected 属性与 SocketConnected() 一起使用?在 volatile 环境中确定套接字状态的最有效方法是什么?

【问题讨论】:

  • 视情况而定。您应该依赖 Connected 属性。即使不是,你通常也不在乎。正常的错误处理必须注意它。调用上述方法后一毫秒可能已经断开连接,这样检查有什么意义?早点意识到?如果您的资源有限,这可能很重要。
  • @Sinatr 所以你说我应该只依赖 Connected 属性?它会做同样的工作,而不必轮询客户端并等待 1 毫秒,对吧?因为我所做的是添加另一个布尔变量并检查属性(例如 bool part3 = s.Connected; if (part1 && part2 && !part3))。资源不是问题,但如果 Connected 属性会给出相同的结果,那么我想没有理由使用 Poll,对吧?

标签: c# sockets


【解决方案1】:

不幸的是,您找到和引用的问题和答案充满了糟糕的建议,并且没有什么真正有建设性的问题可说。面向连接的协议(如 TCP)专门设计用于尽可能长时间地延迟错误,以尽可能多地解决潜在的间歇性传输问题(网络电缆被拔出、无线连接被重置等),以尽量减少这些问题的影响在实际连接上。

对所引用问题的每一个答案都会破坏这一一般策略,或未能以有用的方式解决问题,或两者兼而有之。

处理这种情况的唯一正确方法是假设套接字处于您期望的连接状态(基于您自己的代码操作),同时确保您的代码在每个适当的时候都有异常处理插座的使用点。没有其他办法。

您可以查看Connected 属性,但这不会告诉您任何有用的信息。检查属性后,套接字可能会在一纳秒内转换为未连接状态。您也不应该使用像 Poll() 这样的基于“选择”的方法,因为这些方法效率低下,并且不会随着连接数的增加而扩展。

每个联网程序都可以成功使用异步 I/O。如果程序有 GUI(例如 Winforms、WPF 等),那么您甚至可以这样做,同时仍然在 UI 线程中进行所有实际数据处理(这让您不必过多担心多线程问题......使用现代的async/await 成语会更好,但您也可以只使用“老派”技术,如Control.BeginInvoke()Dispatcher.InvokeAsync())。

因此,遵循这些准则,套接字的连接性以任何有意义、有趣的方式改变状态的唯一时间是当这种情况有意发生时,然后通过正常处理优雅关闭来检测,即完成读取操作结果为零字节,或者由于错误而发生,在这种情况下,您的异常处理将检测到意外断开状态。

如果没有适当的异常处理,您将无法成功编写无缺陷的网络 I/O 代码,因此只有在所有个异常情况下依赖该异常处理才有意义。

【讨论】:

  • 我同意在检查 Connected 属性后套接字可能会断开连接,但我仍然希望将其作为继续执行某些操作的指示符。感谢指出基于选择的方法效率低下,这很明显,但在大多数答案中都没有提到(我对摆脱 Poll() 表示怀疑)、答案的完整性和异常处理.
猜你喜欢
  • 2014-01-31
  • 1970-01-01
  • 1970-01-01
  • 2011-05-07
  • 2018-03-05
  • 1970-01-01
  • 2015-08-29
  • 2011-01-31
  • 1970-01-01
相关资源
最近更新 更多