TCP 有一个保持活动的机制来检测死连接,但让我惊讶的是这个选项在默认情况下是关闭的,而且许多库/工具没有使用这个功能。
如果我理解正确的话,如果来自对等方的所有 FIN/RST 数据包都丢失了,那么在 recv 调用中阻塞的 TCP 连接将无法检测到连接是否实际上已被对等方中止。
客户端的超时参数可能会缓解该问题,但许多库也没有设置超时的选项。一个例子是 mysql-python 连接器没有 recv timeout 选项。另一个例子是 Nginx 服务器使用 proxy_pass 与 gunicorn 后端通信,gunicorn 工作人员可能会由于其上的死连接而停止响应,但 gunicorn 工作人员无法检测到它。
如果我错了,任何人都可以解释原因或纠正我吗?
“死连接”这个词有点含糊不清——它可能意味着以下任何一种:
对等程序关闭了它的套接字(或者对等程序退出或崩溃,并且对等计算机的操作系统关闭了套接字作为其标准进程清理的一部分)
与对等计算机的连接突然中断(这可能是因为对等计算机断电,或者有人拔掉了将对等计算机连接到路由器的以太网线,或者对等计算机的 ISP 出现了路由器故障,或者您的 ISP路由器故障等)
对等程序仍在运行,但只是决定(出于某种原因,可能是由于错误)不再在其 TCP 套接字上调用 recv()。
你的程序和远程对等点之间的数据包路径仍然存在,有点,但是沿着这条路径的东西丢弃了太多的数据包,以至于 TCP 连接的有效传输速率已经下降到大约为零。
那么首先要回答的问题是,TCP层会自行检测上述哪种情况?
条件 (1) 是最简单的情况——对等方的 TCP 堆栈将向您发送 FIN 数据包,当您的程序的网络堆栈接收到它们时,它将确定 TCP 连接已关闭并采取相应措施,因此您的 recv( ) 调用将很快返回 0。
在条件 (2) 中,答案是“有时”——特别是,如果您的程序在套接字的输出缓冲区中有任何 TCP 数据并试图发送给对等方,并且它永远不会收到有关该数据的任何 ACK 数据包,然后在一定次数的超时(以及随后的数据包重发尝试)之后,您计算机的 TCP 堆栈将放弃,声明连接已死,并单方面关闭 TCP 连接;此时 recv() 将返回 0。另一方面,如果没有传出的 TCP 数据包尝试发送,则本地 TCP 堆栈将不会等待任何 ACK 返回,因此它不会当它没有得到它们时就超时,因此它永远不会放弃并关闭 TCP 连接。在这种情况下,您的 recv() 调用可能会无限期地阻塞,因为 TCP 连接是空闲的,并且 TCP 堆栈无法知道对等方已经消失(与现在根本不发送任何数据相反)。SO_KEEPALIVE 选项旨在处理这种情况,但由于 SO_KEEPALIVE 选项的设计者希望在默认情况下节省带宽,并且发送自动保活数据包会占用额外的带宽,因此他们决定默认禁用保活选项。此外,默认的 send-a-keepalive 间隔按照现代标准(例如小时)通常很长,并且在某些操作系统上很难更改,除非在系统范围内进行更改,这使得 SO_KEEPALIVE 对许多应用程序的用处有限。SO_KEEPALIVE 选项旨在处理这种情况,但由于 SO_KEEPALIVE 选项的设计者希望在默认情况下节省带宽,并且发送自动保活数据包会占用额外的带宽,因此他们决定默认禁用保活选项。此外,默认的 send-a-keepalive 间隔按照现代标准(例如小时)通常很长,并且在某些操作系统上很难更改,除非在系统范围内进行更改,这使得 SO_KEEPALIVE 对许多应用程序的用处有限。SO_KEEPALIVE 选项旨在处理这种情况,但由于 SO_KEEPALIVE 选项的设计者希望在默认情况下节省带宽,并且发送自动保活数据包会占用额外的带宽,因此他们决定默认禁用保活选项。此外,默认的 send-a-keepalive 间隔按照现代标准(例如小时)通常很长,并且在某些操作系统上很难更改,除非在系统范围内进行更改,这使得 SO_KEEPALIVE 对许多应用程序的用处有限。
对于条件 (3) 和 (4),TCP 连接并没有真正“死”,只是某些设备(对等程序,或者您的程序和对等方之间某处的网络设备)不合作。由于 TCP 层无法知道正在使用它的应用程序试图实现什么,它明智地不会在这方面尝试对它们进行二次猜测,并且它会保持 TCP 连接打开,除非您明确告诉它关闭( ) 连接。
既然我们已经描述了 TCP 层的行为,那么使用它的应用程序和 API 呢?即为什么他们不尝试通过提供更好的检测来改进基本的 TCP 堆栈行为?答案是他们中的一些人这样做了;例如,通过周期性地跨任何可能空闲的套接字发送虚拟“ping”消息,简单地“刺激”TCP 堆栈以检测何时没有 ACK 返回,如上面关于条件 (2) 的段落中所述。有些人走得更远,期望远程对等方在(这么多)秒内发送相应的“pong”消息在同一个套接字上返回,如果没有,程序将单方面关闭套接字。这种工作,但它也对你的网络性能做出假设,
| 归档时间: |
|
| 查看次数: |
567 次 |
| 最近记录: |