首页 > 解决方案 > 如何在 C# 中有效地确定套接字的状态?

问题描述

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

我正在使用以下函数来确定状态(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 捕获的数据。

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

标签: c#sockets

解决方案


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

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

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

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

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

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

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


推荐阅读