什么是 TCP 窗口缩放?
在 TCP 报头中,窗口大小字段的大小为 16 位。使用此字段,TCP 用户(客户端或服务器)最多可以将 2 16 = 65536 字节或 64 KiB 作为其缓冲区大小通告给其他最终用户。但是现代端点设备(例如,电话、标签、PC 等)的缓冲区中有更多可用内存。在 1980 年代 TCP 的初始设计中,这个 16 位字段就足够了。但是今天内存更便宜,网络非常快,因此情况有所不同。因此,如果端点的缓冲区中有超过 64 KiB 的内存可用于 TCP 连接,它如何使用相同的 16 位窗口大小字段将此信息传递给对等端点?
有两种可能的解决方案:
1. 将窗口大小字段从 16 位增加到 30 位。但这实际上是不可能的。在全球范围内使用 TCP 的所有设备中都无法更新此字段。
2.改变窗口大小的定义。使用比例因子仅使用 TCP 标头中的 16 位字段来传达 30 位窗口大小。这称为窗口缩放。
TCP 标头:
什么是 TCP 窗口缩放?
它解决了“接收窗口”或“广告窗口”或“用户缓冲区”的可伸缩性问题,而无需增加 TCP 标头中“窗口”字段(16 位)的大小。它将窗口字段的“定义”扩展为 32 位,然后使用“比例因子”在 TCP 标头的 16 位窗口字段中携带这个 32 位值。比例因子在一个名为“ Window Scale ”的新 TCP 选项中携带。
TCP 标头中有一个选项字段,旨在适应 TCP 中的所有未来优化。窗口缩放也使用该选项。客户端首先在 SYN 数据包中与服务器共享其缩放因子。当服务器在'SYN'包中接收到客户端的缩放因子时;然后它使用“ SYN+ACK ”数据包中的相同选项字段发送其比例因子,该数据包是客户端发出的连接请求的确认数据包。有一个严格的限制,即在任何其他数据包(客户端首先发送的 SYN 数据包除外)上收到的“窗口缩放”选项应被服务器忽略(服务器不应首先共享其缩放因子)。
Let say client sends SYN packet to server and says that its scaling factor = 2 and receives scaling factor of receiver in ‘SYN+ACK’ packet from receiver.
Now in next packet sender tells its window size = 200 bytes.
Then Server will calculate the real buffer size available at client as: window_size * 22 = 800 bytes.
Client first finds its real buffer size = 800 bytes then it right shifts(reduces) this value 2 times and stores in window size in header and shares with server.
When server receives scaling factor and window size then it left shifts(multiplies) this value 2 times to get real value of client buffer size.
有一点需要注意,当客户端将其在 SYN 数据包中的比例因子共享给服务器时,该比例因子不适用于该数据包。只有当服务器接受它并在 SYN+ACK 数据包中共享其缩放因子时,它才适用。一旦客户端和服务器都预先知道彼此的缩放因子,缩放因子就适用于下一个数据包。从下一个数据包开始,它们不会在每个数据包中发送缩放因子。
我们可以更改窗口缩放因子吗?
很有可能更新窗口缩放因子。当客户端以后再次联系服务器时,它可以再次向服务器指定它的窗口缩放因子,作为回复服务器也会在SYN+ACK包中共享它的窗口缩放因子。现在,如果启用 TFO 会怎样?是的,那么客户端也可以与 GET 请求一起在 SYN 数据包本身中将其更新的窗口缩放因子共享给服务器。作为对此的回复,服务器还将在 ACK 数据包中共享其当前的窗口缩放因子以及 GET 请求的数据。另一种方法是更新窗口缩放因子。客户端应首先删除其 cookie。当 cookie 被删除时,最初的 3 次握手将发生,然后客户端本身可以共享其新的窗口缩放因子。
比例因子在一个名为“ Window Scale ”的新 TCP 选项中携带。 “转移。 cnt”携带缩放值。如果转移。 cnt = 2 然后窗口大小字段值左移 2 次以获得实际缓冲区大小。因此,比例因子 = 2 shift.cnt 。调动,转移。 cnt' 限制为 14。因此,可以使用此选项通告的最大窗口大小为 2 30 = 1 GiB。
16 bits can be stored in window size field. Maximum of 14 bits can be stored in shift.cnt variable. Thus total bits advertised = 16+14 = 30
如果'转移。 cnt' 值大于 14,TCP 将记录错误但仍使用 '14' 而不是 'Window Scale' 选项中指定的较大值。记住!缩放因子仅适用于 TCP 标头的“窗口大小”字段,而不适用于在本地机器中存储“窗口值”的“变量”。
Linux 命令行:
检查 Linux 内核中 TCP Window Scaling 的默认设置
$ sysctl net.ipv4.tcp_window_scaling
预期输出(这意味着 TCP 窗口缩放已启用):
$ net.ipv4.tcp_window_scaling = 1
禁用 TCP 窗口缩放(不推荐,但尝试学习并重新启用)
$ sudo sysctl -w net.ipv4.tcp_window_scaling=0
预期输出:
$ net.ipv4.tcp_window_scaling = 0