具有高 RTT 和重传的套接字 TCP 服务器

具有高 RTT 和重传的套接字 TCP 服务器

我有一个用 Python 套接字构建的 TCP 服务器。我正在构建的应用程序对时间敏感,因此数据的完整性很重要,因此我们需要 TCP。带宽非常低。

客户端每 50 毫秒向服务器请求一次数据。如果服务器没有数据或实际需要的数据,客户端将收到 OK 消息作为响应。

每当客户端向服务器发出请求时,它都会发送一个 5 字节的帧(不包括来自 IP 和 TCP 的 40 个额外字节)。另一方面,服务器要么响应一个 5 字节的帧(大多数情况下),要么响应一个 > 70 字节的帧(通常每秒一次)

两侧插座设置如下:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # this line is excluded in client's case
sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 8192)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
sock.settimeout(0.5)

在本地网络上一切都运行良好(完全没有延迟),但每当我从公共 IP 连接到服务器时(我正在进行端口转发),它都会延迟很多。延迟可能长达 15 秒(此时会超时),这非常多。大多数时候 RTT 保持在 200-210 毫秒。在 WireShark 上我可以看到有很多(虚假的)重传和重复 ACK。

我该怎么办?我已经禁用了 Nagle 算法,但仍然没有成功。

答案1

我仔细查看了提供的捕获文件,以下是我的分析。总而言之,我认为这是你的路由器的问题,这似乎是一个特艺彩色某种装置。

客户端捕获

  • 您的客户端在尝试连接各种网站时遇到严重问题。HTTPS 网站(www.bing.com、wdcp.microsoft.com 等)在客户端问候阶段后没有得到响应,导致重新传输并最终导致您的设备超时。另一组对 Akamai 托管网站 (104.90.152.18) 的 HTTP 请求导致 408 请求超时。
  • 特别查看从客户端到服务器的流量,绝大多数会话开始时都相当正常,但随后会遇到数据包丢失,导致客户端重新传输和超时。例如,检查数据包编号 161 - 207。在数据包 161 处,客户端向服务器发送了一个数据包,但没有收到任何响应,导致客户端在连接断开之前重新传输了大约 15 秒。

    大多数 TCP 流都表现出这种行为,因此我们可以得出结论,要么来自客户端的数据包没有到达服务器,要么来自服务器的响应没有到达客户端。

  • 从延迟来看,服务器的 SYN 和 SYN/ACK 响应之间存在明显(且不稳定)的延迟,范围从 168 毫秒到 770 毫秒。

服务器端捕获

  • 不幸的是,服务器端捕获的事件与客户端捕获的事件不同。我也不确定在网络中的哪个位置捕获了这些事件,因为它包括客户端和服务器流量。还发送了 ICMP 重定向,这表明路由不理想。但我不认为这是导致问题的原因。
  • 如果您应用 wireshark 显示过滤器,则tcp.stream eq 1 || tcp.stream eq 2可以看到通信的双方。具体来说,客户端 > 防火墙,然后是防火墙 > 服务器(反之亦然)。同样,一切开始正常,然后在数据包 407 附近,事情变得有趣起来。

    数据包 #407 标记客户端向服务器发送新数据块的时间点。路由器接收此数据并将其转发到服务器。服务器发回确认数据包(数据包 #410)以及另一个小数据包(#411)。然而,我们没有看到路由器将这些数据包传回客户端- 这是我发现的最好的证据,证明这是一个路由器问题。

将其与跟踪中稍靠前的许多成功交换之一进行比较 - 例如数据包 394 到 406:

  1. (#394)客户端向服务器的公网 IP 发送数据包
  2. (#396)路由器接收该数据包并将其转发到服务器的本地 IP
  3. (#397)服务器向客户端的 NAT 后的 IP 地址发送确认信息
  4. (#398)服务器向客户端的 NAT 后的 IP 地址发送一个小的数据包
  5. (#401)路由器将确认信息发送回客户端的本地 IP
  6. (#402)路由器将小数据包发送回客户端本地IP
  7. (#403)客户端向服务器的公网 IP 发送确认信息,确认已收到服务器发送的数据
  8. (#406)路由器将确认转发到服务器的本地IP。

当出现故障时,一切都会在第 4 阶段之后停止 - 从服务器发送的两个数据包似乎在路由器上被丢弃。

最后的想法

  • 您的大多数 TCP 连接(不仅仅是您的 Python 应用程序)似乎都存在性能问题,这从客户端捕获的许多连接问题可以看出。
  • 您的服务器端捕获中有合理的证据表明,当数据包必须通过路由器转发时,它们被黑洞了。
  • 您的测试得出结论,当流量不需要穿过路由器进行端口转发时,在本地测试此应用程序时不会出现任何问题。
  • 不幸的是,我对 Technicolor 路由器一点都不熟悉,我唯一能建议的是检查路由器上是否启用了任何防火墙或服务质量规则,这可能会影响性能。也许你可以用另一个路由器进行测试,或者在另一个网络中托管你的应用程序,看看问题是否仍然存在。

相关内容