我正在尝试排除家庭互联网连接故障,该连接经常在下载大量数据时挂起。我相信我已经能够通过在两端捕获数据包来复制我家用计算机和 Amazon EC2 实例之间的问题。以下是我在两次不同的挂起中观察到的相同行为:
- 我开始从 EC2 服务器通过 TCP 下载一个 20MB 的文件到我的家用电脑(家用电脑是 TCP 客户端,EC2 服务器是 TCP 服务器)。
- 初始 TCP SYN 的 MSS 选项为 1418 字节。来自客户端的其他段均不具有 MSS 选项(来自服务器的 SYN/ACK 具有 MSS 选项 1460)。
- 当大量传输开始时,来自服务器的数据包为 2878 字节。客户端会收到这两个 1472 字节的数据包(我将它们称为前半部分和后半部分),每个数据包包含一个包含一半数据的 TCP 段。
- 在某个时刻,来自服务器的前半部分数据包丢失。客户端开始使用 SACK 选项重复 ACK。
- 在收到带有 SACK 选项的第一个 ACK 后,服务器开始发送 1472 字节的数据包(而不是 2878 字节的数据包)。
- 在几次重复的 ACK 之后,服务器会执行快速重传,重新发送一个 1472 字节的数据包 - 即不是它最初发送的 2878 字节数据包。此重新发送的数据包不会出现在客户端。
- 超时后,服务器再次尝试重传几次,再次发送 1472 字节数据包。这些重发的数据包均未显示在客户端上。
我有几个问题。首先,为什么服务器一开始就发送 2878 字节的数据包?它不是应该遵守 SYN 数据包中的 MSS 选项吗?
其次,那些 2878 字节的段在哪里被分成两个 1472 字节的段?
第三,所有重传的数据包在哪里被丢弃?为什么被丢弃?
第四,有什么方法可以从客户端来防止这种情况发生?
有趣的是,如果后半部分数据包丢失,连接似乎可以恢复。我的(可能是错误的)理论是,路由中的某些东西正在吞噬重新传输的前半部分数据包,因为它们与原始大小不匹配。此外,通过 UDP 隧道传输的相同传输(使用 OpenVPN)不会挂起(我知道这意味着我可以通过这种方式代理我的所有流量,但这不是我要找的答案)。
后续:@DavidSchwartz 在评论中建议,段大小异常可以通过以下方式解释:传输系统办公室,看起来这是正确的。在服务器上禁用 TSO 会将段大小限制为 1472 字节。不幸的是,传输仍然挂起,因为未收到重新传输的数据包。
我还尝试禁用 TCP 选项 SACK、时间戳和窗口缩放,以及将窗口大小减小到 8192 字节。传输仍然挂起。客户端接收重传数据包之前和之后发送的数据包,但接收不到重传数据包本身。
答案1
我知道这是一篇非常老的帖子,但到目前为止,这两个答案都没有解决禁用选项的问题。通过禁用窗口缩放和 SACK,您已经严重削弱了 TCP。这本身就会导致吞吐量问题。但是,您提到超时后服务器会重新传输几次。这就是问题所在。RTO 已启动指数退避。这意味着连接的另一端在较长时间内完全不可用。这个问题很严重,而不是 TCP 问题,因为 TCP 正在执行其设计要执行的操作。但更可能是路由器等网络设备的硬件问题。