【问题标题】:what is the best way to do keep alive socket checking in .NET?在.NET中保持活动套接字检查的最佳方法是什么?
【发布时间】:2010-09-15 05:06:15
【问题描述】:

我正在寻找一种在 .NET 中进行保持活动检查的方法。该方案适用于 UDP 和 TCP。

目前在 TCP 中,我所做的是一侧连接,当没有数据要发送时,它每 X 秒发送一次保持活动状态。

我希望对方检查数据,如果 X 秒内没有收到,则引发事件左右。

我尝试做的一种方法是进行阻塞接收并将套接字的 RecieveTimeout 设置为 X 秒。但问题是每当超时发生时,套接字的 Receive 会抛出一个 SocketException 并且这一侧的套接字会关闭,这是正确的行为吗?为什么套接字在超时后关闭/死亡而不是继续?

检查是否有数据和睡眠是不可接受的(因为我在睡眠时可能会延迟接收数据)。

那么最好的解决方法是什么,为什么我在另一边描述的方法失败了?

【问题讨论】:

    标签: .net sockets


    【解决方案1】:

    如果您的 tcp 服务器只是以不规则的间隔写入数据,并且您希望在后台保持活动状态:

    tcpClient.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 1);
    tcpClient.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 2);
    tcpClient.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, 2);
    tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
    

    如果服务器不(通常自动)回复 tcp keep alives,将导致异步读取抛出超时异常。

    【讨论】:

      【解决方案2】:

      如果您的字面意思是“KeepAlive”,请尝试以下操作。

          public static void SetTcpKeepAlive(Socket socket, uint keepaliveTime, uint keepaliveInterval)
          {
              /* the native structure
              struct tcp_keepalive {
              ULONG onoff;
              ULONG keepalivetime;
              ULONG keepaliveinterval;
              };
              */
      
              // marshal the equivalent of the native structure into a byte array
              uint dummy = 0;
              byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
              BitConverter.GetBytes((uint)(keepaliveTime)).CopyTo(inOptionValues, 0);
              BitConverter.GetBytes((uint)keepaliveTime).CopyTo(inOptionValues, Marshal.SizeOf(dummy));
              BitConverter.GetBytes((uint)keepaliveInterval).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);
      
              // write SIO_VALS to Socket IOControl
              socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
          }
      

      注意时间单位是毫秒。

      【讨论】:

      • 我很高兴你会回复试图以这种方式帮助你的人。
      • 值得澄清的是,这个答案是 C# 中唯一一个允许您执行 TCP 级别的 keepalives 而不是在代码中手动执行(设置并忘记)并允许您选择超时(使用 SetSocketOption 打开 SocketOptionName.KeepAlive 使用 2 小时超时,对于大多数应用程序来说太长了)。更多信息:blog.stephencleary.com/2009/05/…
      • 我假设这仅在客户端需要。服务器端需要什么?
      【解决方案3】:

      根据 MSDN,在 Receive 调用中超过 ReceiveTimeout 时抛出的 SocketException不会关闭套接字。您的代码中还有其他内容。

      检查捕获的 SocketException 详细信息 - 毕竟它可能不是超时。也许连接的另一端关闭了套接字。

      考虑启用网络跟踪以诊断问题的确切来源:在 MSDN 上查找“网络跟踪”(无法为您提供链接,因为现在 MSDN 已关闭)。

      【讨论】:

      • 实际上另一方仍然认为套接字是打开的(而这一方没有)。这部分代码并不复杂,我会尝试在较小的测试用例中重现它。
      【解决方案4】:

      由于您不能使用阻塞(同步)接收,您将不得不接受异步处理。幸运的是,使用 .NET 很容易做到这一点。查找 BeginReceive() 和 EndReceive() 的描述。或查看此articlethis

      至于超时行为,我没有找到明确的描述。由于没有记录,否则您必须假设这是预期的行为。

      【讨论】:

      • 是的,忘了提到异步操作,但我想我的问题是有没有人有 RecieveTimeout 的经验以及为什么它以上述方式失败(因为这样我的代码会比使用 RecieveTimeout 更容易。
      猜你喜欢
      • 1970-01-01
      • 2011-01-03
      • 1970-01-01
      • 1970-01-01
      • 2017-04-28
      相关资源
      最近更新 更多