【问题标题】:Too slow socket response (21 seconds) using TCP protocol使用 TCP 协议的套接字响应太慢(21 秒)
【发布时间】:2015-03-13 21:42:49
【问题描述】:

我正在尝试创建套接字并连接到设备。当设备不在网络中并且我尝试连接时会出现问题。我得到错误的响应(这没关系,我更新设备状态的依据是),但问题是我在 21 秒内得到响应。我正在使用此功能进行连接:

public bool Connect(IPEndPoint ipEndPoint, IPAddress ipAddress, Guid id, bool isAlive)
{
    try
    {
          clSocket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
          clSocket.NoDelay = false;
          clSocket.ReceiveTimeout = 1000;
          clSocket.SendTimeout = 1000;
          clSocket.Connect(ipEndPoint);
          return true;
     }
     catch (Exception ex)
     {
          return false;
     }
}

尽管我读到“21 秒超时”,但我发现我必须更改寄存器:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters
值名称:TcpMaxDataRetransmissions
数据类型:REG_DWORD - 数字
有效范围:0 - 0xFFFFFFFF
默认值:3

我正在参考这篇文章:
http://getin2me.blogspot.com/2010/08/are-you-also-facing-windows-sockets-21.html
和这篇文章:
https://social.msdn.microsoft.com/Forums/en-US/fd586377-34b3-4cb8-a3af-0a24c608e399/connectex-winsock-question?forum=vcgeneral

为什么在 Windows 8 中我找不到这个寄存器?有没有其他解决方案可以让我快速(快速我的意思是正常

【问题讨论】:

  • 这些注册表项默认情况下不存在。它们仅用于延长超时。
  • 所以我应该添加它们还是...?

标签: c# sockets networking network-programming


【解决方案1】:

快速我的意思是正常

如果设备不存在,您将无法快速获得有关连接失败的响应。 TCP 连接由3-way-handshake 建立。在此握手中,客户端首先向服务器发送一个 SYN 数据包并等待 SYN+ACK 返回。

  • 如果服务器在那里,但端口已关闭,它将返回 RST(而不是 SYN+ACK),并且客户端知道服务器无法访问。这可以在 RTT 时间内完成,这在本地网络中是几毫秒,但如果您在互联网上,则很容易超过 20 毫秒。
  • 如果服务器不存在,则无法发回响应。在这种情况下,客户端将多次重试发送 SYN,因为数据包可能会丢失。等待响应的时间取决于操作系统和调整,但通常第一次重试在 1 秒后完成,第二次在 3 秒后完成……直到一段时间后客户端简单地放弃并假设服务器不在那里.这意味着在这种情况下,这将需要几秒钟的时间,而您对此无能为力。

【讨论】:

  • 我完全同意您所写的一切,但是如果您阅读我发布的文章,您会发现可以设置 TcpMaxDataRetransmissions 并调整操作系统以在第一次通话后放弃。你知道我如何在 Win8 中调整它吗?
  • 不,我没有。但即使你这样做,也很难在 20 毫秒内得到响应,因为操作系统可能会等待更长时间才能放弃。在服务器启动的许多情况下,只尝试一次会导致连接失败,因为不时丢失数据包实际上是一种正常行为。
  • 好的,我会说合理的时间不是 20 毫秒,但要实现这一点,我需要将等待响应的时间,而不是 3 秒、6 秒、12 秒(总共 21 秒)更改为更低的值。
  • 我不知道如何在 Windows 中调整它,但您可以使用非阻塞套接字,从而完全控制等待的时间。例如,请参阅codeproject.com/Tips/168704/…。这样做的好处是它只适用于单个套接字,而不适用于系统上的所有套接字,就像在注册表中进行全局调整一样。
【解决方案2】:

你可以先ping一下地址,看看有没有响应,如果没有,就不要尝试连接了

Ping pinger = new Ping();
try
{
    PingReply reply = pinger.Send(ip);
    if (reply.Status == IPStatus.Success)
    {

    }
    else
    {

    }
}

【讨论】:

  • 如果我在 Connect 函数上得到 true 或 false 不是问题,问题是超时。 Ping 是不同的,如果您可以 ping 并不意味着您可以将数据包发送到设备。所以这并不能解决我的问题。
  • Ping (ICMP) 经常被防火墙阻止,而与特定端口的 TCP 连接则不会。
猜你喜欢
  • 1970-01-01
  • 2018-06-25
  • 1970-01-01
  • 2011-01-23
  • 1970-01-01
  • 2019-02-13
  • 1970-01-01
  • 1970-01-01
  • 2015-07-10
相关资源
最近更新 更多