Python:TCP 损坏的路由检测速度非常慢

Posted

技术标签:

【中文标题】Python:TCP 损坏的路由检测速度非常慢【英文标题】:Python: TCP broken route is painfully slow to detect 【发布时间】:2016-08-24 11:51:42 【问题描述】:

我在使用 Python3/asyncio(Protocol) 编写的服务器应用程序时遇到了问题,但我很确定它与 python 或 asyncio 相关的并不多,因为我已经尝试了不同的版本,也有一些 5liner 仅使用套接字接口。 它是关于与许多客户端硬件 TCP/IPRS232 转换器的并发通信。这就是使用 asyncio 而不是阻塞写入的线程的原因。

有一些周期性的短数据发送。当我物理切断连接并等待异常发生时会出现问题:

asyncio - Fatal read error on socket transport protocol
<_SelectorSocketTransport fd=11 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
File "/usr/lib/python3.5/asyncio/selector_events.py", line 663, in
_read_ready
data = self._sock.recv(self.max_size)
OSError: [Errno 113] No route to host

发生了,但是在 15 分钟 之后,这意味着我在 15 分钟内发出信号,一切都很好,但事实并非如此,这太长了并且功能中断。 在 Ubuntu 16.04、Ubuntu 14.04 和 Debian Jessie 中检查的行为,都在不同的硬件上。

我发现(可能)内核正在缓冲数据,因为如果我在十分钟后重新连接设备,所有数据都会立即刷新。我知道这对短时间断开有好处,我对 10 秒、15 秒甚至一分钟都没有问题,但 15 分钟太多了。

通过实现应用程序协议回答了类似的问题,这在我的情况下是不可能的。 我只是想确保对方在合理的时间内收到数据包(TCP ack)。 我仔细阅读了有关socket.setsockopt 的文档,但没有发现任何有用的东西。也没有找到方法如何检查发送缓冲区是否被刷新以做一些解决方法 - 手动检测损坏的路由。

TCP keep-alive 也无济于事,因为它基于非活动时间,发送数据即为活动。

【问题讨论】:

【参考方案1】:

您正在看到 TCP 的重新传输超时 (RTO) 行为。

您的 TCP 从未收到任何反馈¹,因此它会非常努力地让这些段通过。在 Linux 上,此行为由 net.ipv4.tcp_retries2 = 15 控制:

这个值会影响 TCP 连接的超时时间,当 RTO 重传仍然未被确认。给定 N 的值,a 指数退避后假设的 TCP 连接 TCP_RTO_MIN 的初始 RTO 将在终止之前重传 N 次 在第 (N+1) 个 RTO 处连接。

默认值 15 产生 924.6 秒的假设超时 并且是有效超时的下限。 TCP 将有效地 在第一个超过假设超时的 RTO 处超时。

这意味着您的send 显然有效(即,TCP 最终同意发送您的数据)并且您等待 TCP 继续重试约 900 秒。

更改应用程序协议是解决此问题的有效方法,但由于您提到它对您不起作用,您的选择围绕着询问 TCP。

TCP_USER_TIMEOUT 似乎完全符合您的要求:

当值大于0时,指定最大数量 传输数据可能保持未确认状态的时间(以毫秒为单位) 之前TCP会强制关闭相应的连接并返回 ETIMEDOUT 给应用程序。

关于Application Control of TCP retransmission的更多详情。

也没有找到如何检查发送缓冲区是否被刷新的方法 一些变通方法——手动检测断路。

上面链接的问题有SIOCOUTQ - 检查输出队列中的数据量 - 作为您描述的解决方法。


¹例如,它可能会收到 TCP RST 或 ICMP 无法访问。

【讨论】:

以上是关于Python:TCP 损坏的路由检测速度非常慢的主要内容,如果未能解决你的问题,请参考以下文章

TCP 校验和能否检测到错误?如果是,如何处理?

VMware虚拟机配置文件(.vmx)损坏修复

TCP/UDP/HTTP

如何在 Apache Camel 中检测损坏/恢复的 JMS 连接?

怎么检测PDF文件是不是损坏

如何检测PDF文档是不是损坏了?