TCP滑动窗口

背景

在分析TCP滑动窗口之前我们先回想一下,关于TCP的特性都有哪些。

①面向连接②有序性③重传机制④可靠传输⑤流量控制 ··· (本篇就用到这么多)

第一个特性面向连接不必多说,通过三次握手实现。

第二个特性有序性,这个也不必多说。TCP会将数据包分段并添加序列号进行传输。

第三个特性重传机制,这个特性就很关键了,它是TCP可靠传输的关键,也是滑动窗口机制的关键。总之就是关键中的关键。重传机制也就是当发送方认为数据段在传输过程中丢失的时候(没有获取到回复的ACK),会进行重传,那么发送方是如何判断数据段已经丢失了呢?这就得靠RTT和RTO了。RTT是发送数据段到接收到这个数据段得ACK的时间差。通过这个时间差RTT,TCP就可以计算出RTO,也就是重传定时器的时间。当发送端发送数据段,RTO开始倒计时,直到倒计时结束后都没有收到ACK时,发送端则会进行数据包的重传。

第四个特性可靠传输,既然是可靠传输则接收方接收必须对数据进行校验,TCP通过数据包分段并将其添加序列号实现对数据包的校验。那问题来了,既然发送的时候包是有序的,接收的时候包是否依旧有序呢?答案当然是否定的,我们必须假设网络是不安全的,数据段在传输过程中很可能出现丢失。既然接收的数据段无法保证有序,那么TCP必须得依赖一个机制保证接收到得数据段是有序的,这个机制便是滑动窗口机制

第五个特性流量控制,为什么要实现流量控制?因为我们无法确定发送端和接收端的网络情况是否一致,假设接收端此刻网络拥塞,最多只能接收50个数据段,而发送端却发送了100个数据段,这样就造成了不必要的资源浪费。为了保证双方的数据传输流量一致,TCP采用了滑动窗口机制

以上我们在TCP的有序性中说了,TCP会将数据拆分成段进行发送。然而TCP并不能一段一段地发送数据然后等待收到上一段数据的ACK后再发送下一段数据,这样效率未免也太低了。于是TCP为了实现数据段的批量发送,就必须要解决可靠传输以及包乱序的问题。此时,滑动窗口机制便登场了。

我们先了解一下何为滑动窗口机制:

滑动窗口机制

滑动窗口分为2类,发送窗口和接收窗口,发送端通过ACK的window字段(TCP首的window字段)动态调节发送窗口大小(窗口大小决定了发送的数据量);接收端通过计算自己最多还能接收多少数据,动态调节接收窗口大小并通过ACK告知发送端。

现在我们已经简单的了解了滑动窗口机制是怎么运作的,那么抛出问题了:

发送窗口和接收窗口

对于发送端,其发送缓存中的数据可以分为4类
在这里插入图片描述

  1. 发送了且接收到ACK验证
  2. 发送了但是没有接收到ACK验证
  3. 没有发送但对端允许发送
  4. 没有发送但对端不允许发送

而我们上面说的发送窗口,就是2和3的连续空间了。为什么呢?
因为分类1数据已经收到ACK确认,我们可以不用再管。

分类2数据发送了但是我们需要等待ACK,如果在RTO时间内没有等到ACK还需要通过发送窗口进行重传。此时如果收到了来自接收方的ACK,发送窗口会移动至下个位置。

这里补充一个点:之前说过发送端发送了一批数据段,不可能等待所有的ACK确认才移动发送窗口,这样效率太低,那么如何提高效率呢?TCP只能从接收端发送ACK的机制下文章了。TCP采用了肯定确认技术,也就是接收端ACK指下一个期待的字节,例如接收端窗口范围是从32-51,收到了32-40和45-51的数据,这时接收端只会发送一个41的ACK,告知发送端从41开始批量发送数据段。这样就不仅避免了发送端每次都要确认ACK造成不必要的资源损失,同时还可以进行数据的校验,TCP的有序性就是这样完成的

分类3数据还未发送,但是即将通过发送窗口发送。分类4,代表将来要发送的数据,但根据目前的接收窗口缓存剩余量它们是不允许被发送的。

对于接收方,其接收缓存中的数据可以分为3类
在这里插入图片描述

  1. 收到数据并且回复了ACK
  2. 还未收到但允许接收(这里也有可能是收到了序列号不连续的数据段但是根据确认原则接收方无法进行接收确认并回复ACK,下面会详细说)
  3. 未收到但不允许接收

接收窗口为什么是区域2也很好理解。
分类1收到且回复了ACK则不必再管。

分类2,未收到是一种情况,还有一种情况是收到了但是无法进行确认,例如收到了32—35和37—51的数据段,少了36,这时接收窗口只会移动到35(窗口内从36开始),并给发送端回复一个ACK告知期望获得36的数据段,这时接收端又得从36开始发送一批数据段。接收窗口只有在前面所有的段都确认的情况下才会移动,以此确保对端会对这些数据重传。

而分类3,因为接收缓存大小不足以接收来自发送方的数据时,则不允许接收。

到这里,我们已经对发送窗口的运作机制了解的差不多了,那么再抛出一个问题,发送端是如何得知能够给接收端发送多少数据呢,接收端又如何判断自己可以接收多少数据呢?

发送端,接收端如何计算window

在这里插入图片描述

接收端计算AdvertisedWindow

作为接收端时可以通过计算AdvertisedWindow(可接收的数据大小)用于告知发送方动态调整window size。
LastByteRead也就是接收端已经接收且回执ACK的最后一个数据段序列号
NextByteExpected也就是接收端已经接收但还未回执ACK的数据段序列号
LastByteRcvd也就是接收端已经接收但无法进行回执ACK的数据段序列号(因为中间空白区域有一些数据丢失,所以无法回执ACK)

AdvertisedWindow = MaxRcvBuffer(接收方缓存池大小)- (LastByteRcvd -LastByteRead)

上面的太抽象我们通过实例说明
在这里插入图片描述
我们假设接收方接收缓存大小为90,其中20-80必须要预留空间等待接收,则AdvertisedWindow = 90 - ( 80 - 20) = 30

也就是接收方发送ACK时,会附带这个AdvertisedWindow,告知发送方此时我可以再接收30个数据段。

发送端计算EffectiveWindow

作为发送端时可以根据接收端的回执ACK中的AdvertisedWindow(剩余可发送的数据大小)计算出EffectiveWindow(窗口内剩余的可发送的最大数据量),以此动态调节window size以控制发送数据段的数量

LastByteAcked也就是发送端已发出且已收到接收端ACK的最后一个数据段序列号
LastByteSent也就是发送端已发出但是未收到接收端ACK的最后一个数据段序列号
LastByteWritten也就是发送端未发出但是等待发出的最后一个数据段序列号

EffectiveWindow = AdvertisedWindow - (LastByteSent - LastByteAcked)

发送方此时已经得知,接收方此时能承受AdvertisedWindow这么多的数据量,LastByteSent - LastByteAcked这个区域的数据是已经发送但还未收到ACK的,发送方假设可能会对这部分数据进行重传,所以会减去这部分的大小。其结果EffectiveWindow也就是发送端还能发出多少数据。

这个过程如下图所示。
在这里插入图片描述
当收到来自接收方新的ACK时,发送窗口就会进行滑动,之前有说过原滑动窗口包含了已经发送但未收到ACK确认的数据段未发送但等待发送的数据段
我们假设已发送但未确认的数据段序号为32-40,41-51为未发送但等待发送的数据段,此时只有当收到32-40序号的ACK时,窗口才可以滑动。

假设此时收到ACK序号36的数据段,窗口移动到36,此时37-40则是已发送但未收到ACK的数据段。同时根据ACK中的AdvertisedWindow计算出EffectiveWindow,假设AdvertisedWindow=30,那么EffectiveWindow = 30 - (40 - 37 ) = 27,此时发送窗口size扩大,41 - 68的数据段都属于发送但未收到确认的数据段未发送但等待发送的数据段。window size 由原来的19 扩大到 现在的 30。这就是一个滑动窗口进行流量控制的场景

到此为止我们已经明白了何为滑动窗口机制,滑动窗口机制是如何进行数据校验实现有序性的,滑动窗口机制是如何进行流量控制的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值