TCP 滑动窗口的大小
场景
我们在用 tcpdump 分析 tcp 数据段时, 数据中会有一个 win 变量, 如
20:59:17.766879 IP 192.168.113.89.50179 > www.test.com.http-alt: Flags [.], ack 21379872, win 32768, length 0
这个 win 代表了什么意思呢?
滑动窗口
TCP 协议为了达到更高效的数据发送效率, 会使用一个叫滑动窗口的机制来批量发送数据, 其形式如图
图中 1~1000 为一个 MSS (Max Segment Size) 大小, 如果窗口大小是 4 MSS, 表示一个窗口可以同时发送 4 个段的数据 (1~4000), 也就是说 1001~2000 的数据可以不必等到 1~1000 的 ack 就直接发出去. 同时, 下一次发送的数据, 将会直接移动到收到的 ack 的最大编号开始, 而不必管前面的编号数据有没有收到 ack. 如图
窗口的大小
那么, 窗口的大小是如何确定的呢?
窗口控制
tcp 的接收方可以根据自己对网络数据的消费能力, 给数据发送方发送一个窗口大小控制参数, 这个参数就是 tcpdump 中看到的 win. 当消费能力不足时, 有可能窗口大小会变成 0. 这样, 发送方便不会再给接收方发数据. 在这期间, 发送方会时不时发一个"窗口探测"数据段, 这个数据段用于获取接收方的最新窗口控制参数. 当窗口大小恢复时, 数据传输才得以继续.
拥塞控制
发送方在数据传输开始时, 如果刚开始就发送大量数据, 很可能会造成网络拥堵. 那么, 窗口大小是如何定义的呢?
tcp 有个机制叫慢启动. 一般来讲, 如果 MSS 为 1460 Bytes (以太网标准), 则窗口初始大小设置为 3 MSS 大小. 此后, 根据每次数据往返的 ack, 会逐渐增大这个值. 首次开始数据传输时, 拥塞窗口大小会以 1, 2, 4 这样的指数倍增长, 直到发生超时重发, 窗口会重新开始计算, 并设置一个慢启动阈值, 这个阈值为窗口大小的一半, 当窗口大小超过阈值时, 窗口的增长速率按照一个小于 MSS 大小的比例增长, 公式为
如果遇超时重传的情况, 则拥塞窗口大小会重新设置为 (慢启动阈值 + 3 MSS). 而阈值会重新设置为当前窗口的一般. 窗口变化如图
窗口大小的确定
那么, 最终的窗口大小其实是由接收方的窗口控制参数和拥塞窗口大小共同决定的, 实际发送的窗口数据量大小, 是两者中的较小值.