IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

TCP 滑动窗口 与窗口缩放因子(Window Scaling)

并发编程网 – ifeve.com 2019-01-01 19:59:27 累计浏览 2,104 次
本机暂存

一、前言

说道TCP滑动窗口协议,相信大家都很熟悉,但是说道 Window Scaling参数或许知道的和用过的人却不多,本文我们来谈谈Window Scaling的由来。

二、TCP滑动窗口

众所周知,TCP是一种面向连接可靠消息传输协议;为了保证可靠,连接的两端保持对所有传输数据的严格跟踪,以便在需要时候进行重传或重新排序。另外为了跟踪已经发送了的数据在发送端有TCP发送缓存,在接受端有接受缓存,滑动窗口则是这个缓存的一部分,接收方接受数据后会把ack和当前滑动窗口可用空间告诉发送方,发送方则发送的数据不能超过接收方剩余窗口大小,如果接收方窗口内数据还没来得及由应用程序读取,窗口满了,则发送方会停止发送数据,直到接收方滑动窗口有空间。

假设我们有两个主机A和B,它们建立了一个TCP连接。在连接开始时(握手时候协商),两个主机为传入数据分配32 KB的缓冲区空间,因此每个主机的初始窗口大小为32,768。
image.png

主机A需要向主机B发送数据,一开始则主机B告诉主机A在接受自己确认之前最多可以发送32,768字节的数据(以最大段大小或MSS的间隔) 。假设MSS为1460字节,主机A可以在耗尽主机B的接收窗口之前发送22个段。

当确认收到主机A发送的数据时,主机B可以调整其窗口大小。例如,如果上层应用程序仅处理了一半缓冲区,则主机B会将其窗口大小降低到16 KB(这时候主机A在接受到B的确认前最多发送16KB数据到B)。如果缓冲区仍然完全填满,主机B会将其窗口大小设置为零,表明它还不能接受更多数据,这时候主机A则停止发送数据。
image.png

在具有高带宽和极低延迟的LAN上,滑动窗口很少会满。但是,在高带宽,高延迟网络上,会出现一个有趣的现象:在发送方接受到接收方发出确认之前,并不能最大化利用带宽。

例如,假设在通过专用10 Mbps路径连接的两台主机之间建立TCP连接,单向延迟为80ms。两个主机都约定最大窗口大小为65,535字节(16位无符号整数的最大值)。我们可以计算在一个时间点在一个方向上传输的潜在数据量,带宽*延迟:10,000,000 bps除以每字节8位,乘以0.08秒等于100,000字节。

换句话说,如果主机A开始连续发送给主机B,它将在主机B接收到发送的第一个字节之前发送100,000个字节。但是由于约定的最大接收窗口只有65,535字节,所以主机A必须在发送65,535字节后停止发送,并等待来自主机B的确认。(为简单起见,我们的示例计算不考虑TCP和低层报头。)这种延迟浪费了潜在的吞吐量,不必要地增加了通过网络可靠传输数据所需的时间。创建TCP窗口缩放以解决此问题。

三、窗口缩放因子

窗口缩放在RFC 1072中引入并在RFC 1323中进行了改进。实际上,窗口缩放只是将16位窗口字段扩展为32位长度。解决方案是定义TCP选项以指定计数,通过该计数,TCP标头字段应按位移位以产生更大的值。
image.png
如上图 window size设置为5840字节,但是窗口缩放因子为7(window scale),也就是这时候最大实际窗口为 5840*128。window scale为1将字段的二进制值向左移位一位,使其加倍。计数为2将值向左移动两位,使其翻倍。计数为7(如上例所示)将该值乘以128.
image.png

窗口缩放选项(window scaling)可以在tcp握手时候在SYN分组中的连接期间仅发送一次。可以通过修改TCP标头中的窗口字段的值来动态调整窗口大小,但是在TCP连接的持续时间内,标度乘数保持静态。仅当两端都包含选项时,缩放才有效;如果只有连接的一端支持窗口缩放,则不会在任一方向上启用它。最大有效比例值为14(RFC 1323的2.3节为有兴趣的人提供了一些背景信息)。

回顾我们之前的示例,我们可以观察窗口缩放如何使我们能够更有效地进行网络传输(最大化利用网络带宽)。为了计算我们的理想窗口,我们将端到端延迟加倍以找到往返时间,并将其乘以可用带宽:2 * 0.08秒* 10,000,000 bps / 8 = 200,000字节。为了支持这种大小的窗口,主机B可以将其窗口大小设置为3,125,其window scaling因子为6(3,125左移6乘以200,000)。幸运的是,这些计算都是由现代TCP / IP堆栈实现自动处理,无须应用程序层面干预。

在应用实战中,我们的文件上传服务上传图片时候还好,但是上传大视频时候就发现很慢,一个8M的视频上传需要1分钟30s,我们增大tcpbuffer和开启了缩放因子调优后,8M视频只需要20s

四、参考

http://packetlife.net/blog/2010/aug/4/tcp-windows-and-window-scaling/

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. gen_tcp发送进程被挂起起因分析及对策 (累计阅读 37,821)
  2. TCP 的那些事儿(上) (累计阅读 22,696)
  3. 从输入 URL 到页面加载完成的过程中都发生了什么事情? (累计阅读 15,933)
  4. 自建DNS以防止GFW干扰 (累计阅读 13,125)
  5. 浅谈TCP优化 (累计阅读 11,081)
  6. 推荐一些socket工具,TCP、UDP调试、抓包工具 (累计阅读 10,843)
  7. 查看 Apache并发请求数及其TCP连接状态 (累计阅读 10,068)
  8. 推荐一些socket工具,TCP、UDP调试、抓包工具 (累计阅读 8,840)
  9. websocket 连接 C Server的尝试 (累计阅读 7,922)
  10. 计算机网络协议包头赏析-TCP (累计阅读 7,853)