专栏首页Java编程技术TCP 滑动窗口 与窗口缩放因子

TCP 滑动窗口 与窗口缩放因子

一、前言

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

二、TCP滑动窗口

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

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

image.png

主机A需要向主机B发送数据,一开始则主机B告诉主机A可以在自己接受主机B确认之前传输最多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 scaleing)可以在tcp握手时候在SYN分组中的连接期间仅发送一次。可以通过修改TCP标头中的窗口字段的值来动态调整窗口大小,但是在TCP连接的持续时间内,标度乘数保持静态。仅当两端都包含选项时,缩放才有效;如果只有连接的一端支持窗口缩放,则不会在任一方向上启用它。最大有效比例值为14(RFC 1323的2.3节为有兴趣的人提供了一些背景信息)。

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

四、参考

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • httpClient连接池管理,你用对了?

    因为使用它可以有效降低延迟和系统开销。如果不采用连接池,每当我们发起http请求时,都需要重新发起Tcp三次握手建立链接,请求结束时还需要四次挥手释放链接。而链...

    加多
  • Java中调度线程池ScheduledThreadPoolExecutor原理探究

    前面讲解过Java中线程池ThreadPoolExecutor原理探究,ThreadPoolExecutor是Executors中一部分功能,下面来介绍另外一部...

    加多
  • httpclient连接池管理,你用对了?

    因为使用它可以有效降低延迟和系统开销。如果不采用连接池,每当我们发起http请求时,都需要重新发起Tcp三次握手建立链接,请求结束时还需要四次挥手释放链接。而链...

    加多
  • 某移动应用安全加固与脱壳技术研究与实例分析

    xfkxfk
  • HBase RowKey 设计

    HBase中 RowKey 用来唯一标识一行记录。在 HBase 中检索数据有以下三种方式:

    smartsi
  • 设计HBase RowKey需要注意的二三事

    这对Scan操作非常友好,因为RowKey相近的行总是存储在相近的位置,顺序读的效率比随机读要高。

    王知无
  • 理论有何用?不问“何用”,先问“用否”!

        昨天准备写点东西,把原来同事的代码拿过来看看,这位同事有数年大型国企、数年知名外企工作经验,而且“案头”常放一部厚案头的“设计模式”方面的书,但我之前从...

    用户1177503
  • 学习zepto.js(原型方法)[1]

    学习zepto.js(原型方法)[1] 新的一周,新的开始,今天来学习一下zepto里边的原型方法,就是通过$.进行调用的方法,也是可...

    贾顺名
  • 不够聪明所以选择工程?

    曾经听一个面试者说过:因为觉得自己不够聪明所以选择了工程,如果自己足够聪明的话就去做算法了。对于他这段话我思考的很久,最后的结论是:Are you kiddin...

    静儿
  • 关于批量插入:Python sqlite

       个人遇到了一个需要互操作 Access 与 sqlite 的项目,其中涉及了诸多 join 和 relation。最重要的是数据的互相流动,这个项目使用...

    py3study

扫码关注云+社区

领取腾讯云代金券