如何允许 TCP 窗口大小大于以太网数据包的最大大小?
TCP 窗口大小通常与最大段大小无关,最大段大小取决于最大传输单元,而最大传输单元又取决于最大帧大小。
让我们从低处开始。
最大帧大小是网络(段)可以传输的最大帧。对于以太网,根据定义,这是 1518 字节。
帧封装了一个IP包,所以最大的包——最大传输单元MTU——是最大帧大小减去帧开销。对于以太网,这是 1518 - 18 = 1500 字节。
IP 数据包封装了一个TCP 段,因此最大段大小MSS 是 MTU 减去 IP 开销减去 TCP 开销(MSS 不包括 TCP 标头)。对于没有选项的以太网和基于 IPv4 的 TCP,这是 1500 - 20 (IPv4 开销) - 20 (TCP 开销)) = 1460 字节。
现在,TCP 是一种传输协议,它将自己呈现为应用程序的流套接字。这意味着应用程序可以通过该套接字传输任意大小的数据 - 在单个流或任意数量的块中。为此,TCP 将数据流拆分为所述段(0 到 MSS 字节长 {1}),通过 IP 传输每个段,然后将它们放在一起回到目的地。在应用程序级别,数据流在源和目标上看起来完全相同。所有的分段、打包、分片等都是完全透明的。
TCP 段由目的地确认以保证传送。现在假设源节点只发送一个段,等待确认,然后发送下一个段(发送窗口 = MSS)。不管实际带宽如何,此 TCP 连接的吞吐量将被限制为每个往返时间(RTT,数据包从源到目的地再返回所需的时间)一个数据包。
因此,如果两个节点之间的连接速度为 1 Gbit/s,RTT 为 10 ms,则可以有效地每 10 ms 发送 1460 个字节,即 146 kB/s。这不是很令人满意。
因此,TCP 使用了一个发送窗口——多个段可以同时“在飞行中”,被发送出去并等待确认。它也称为滑动窗口,因为每次确认窗口开头的段时它都会前进,从而触发窗口前进到的下一个段的发送。这样,段大小无关紧要,只是发送窗口大小。使用传统上 64 KiB 的窗口,我们可以在飞行中获得该数量,因此,每 10 ms = 6.5 MB/s 传输 64 KiB。更好,但仍然不能满足千兆连接。
现代 TCP 使用窗口缩放选项,可以将发送窗口以指数方式增加到高达 64 KiB * 2 14 = 1 GiB,从而为未来的增长做好准备。
但是为什么不是一次发送所有数据,为什么我们需要这个发送窗口呢?
如果您尽可能快地发送所有内容 - 本地 - 并且(很可能)在通往目的地的路径上的某个地方存在较慢的链接,则需要将大量数据排队。没有交换机或路由器能够缓冲超过几 MB(如果有的话),因此需要丢弃多余的流量。如果确认失败,则需要重新发送,多余的部分将再次被丢弃。这将是非常低效的,并且会严重拥塞网络。TCP 通过拥塞控制来处理这个问题,根据(估计的!)有效带宽和当前往返时间在复杂算法中调整窗口大小。
{1} 使用keepalive选项可以使用空段来防止连接超时。Thx 重复数据删除器