本文主要是介绍TCP传输协议---滑动窗口、流量控制,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
滑动窗口、流量控制
- 一. 滑动窗口协议
- ①. 滑动窗口介绍
- ②. 传统方式传输
- ③. 滑动窗口传输方式
- ④. 窗口大小
- ⑤. 发送方的滑动窗口
- ⑥. 数据全部发送完毕
- ⑦. ACK确认应答
- ⑧. 接收方的滑动窗口
- ⑨. 接收窗口和发送窗口的大小
- 二. 流量控制
- ①. 流量控制
- ②. 操作系统缓冲区与滑动窗口
- ③. 收缩窗口、丢包的现象
- ④. 窗口关闭
- ⑤. TCP 解决窗口关闭时,潜在的死锁现象
- ⑥. 糊涂窗口综合症
- ⑦. 解决糊涂窗口综合症方法
一. 滑动窗口协议
①. 滑动窗口介绍
-
窗口对应的是一段可以被发送者发送的字节序列,其连续的范围称之为窗口;
-
滑动则是指这段“允许发送的范围”是可以随着发送的过程而变化的,方式就是按顺序滑动。
②. 传统方式传输
- TCP 是每发送一个数据,都要进行一次确认应答。当上一个数据包收到了应答了, 再发送下一个。
传输方式有一个缺点:数据包的往返时间越长,通信的效率就越低。
③. 滑动窗口传输方式
- TCP 引入了窗口,就可以指定窗口大小,窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。
- 即使在往返时间较长的情况下,它也不会降低网络通信的效率。
用滑动窗口方式并行处理
- 图中的 ACK 600 确认应答报文丢失,也没关系,因为可以通过下一个确认应答进行确认,只要发送方收到了 ACK 700 确认应答,就意味着 700 之前的所有数据「接收方」都收到了。这个模式就叫累计确认或者累计应答。
④. 窗口大小
TCP 头里有一个字段叫 Window,也就是窗口大小。
-
这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。
-
所以,通常窗口的大小是由接收方的窗口大小来决定的。
-
发送方发送的数据大小不能超过接收方的窗口大小,否则接收方就无法正常接收到数据。
⑤. 发送方的滑动窗口
- 发送方缓存的数据,根据处理的情况分成四个部分,其中深蓝色方框是发送窗口,紫色方框是可用窗口:
- #1 是已发送并收到 ACK确认的数据:1~31 字节
- #2 是已发送但未收到 ACK确认的数据:32~45 字节
- #3 是未发送但总大小在接收方处理范围内(接收方还有空间):46~51字节
- #4 是未发送但总大小超过接收方处理范围(接收方没有空间):52字节以后
⑥. 数据全部发送完毕
- 当发送方把数据「全部」都一下发送出去后,可用窗口的大小就为 0 了,表明可用窗口耗尽,在没收到 ACK 确认之前是无法继续发送数据了
⑦. ACK确认应答
- 当收到之前发送的数据 32~36 字节的 ACK 确认应答后,如果发送窗口的大小没有变化,则滑动窗口往右边移动 5 个字节,因为有 5 个字节的数据被应答确认,接下来 52~56 字节又变成了可用窗口,那么后续也就可以发送
SND.WND、SND.UN、SND.NXT
-
SND.WND:表示发送窗口的大小(大小是由接收方指定的);
-
SND.UNA:是一个绝对指针,它指向的是已发送但未收到确认的第一个字节的序列号,也就是 #2 的第一个字节。
-
SND.NXT:也是一个绝对指针,它指向未发送但可发送范围的第一个字节的序列号,也就是 #3 的第一个字节。
-
指向 #4 的第一个字节是个相对指针,它需要 SND.UNA 指针加上 SND.WND 大小的偏移量,就可以指向 #4 的第一个字节了。
可用窗口大 = SND.WND -(SND.NXT - SND.UNA)
⑧. 接收方的滑动窗口
接收窗口处理的情况划分成三个部分:
- #1 + #2 是已成功接收并确认的数据(等待应用进程读取);
- #3 是未收到数据但可以接收的数据;
- #4 未收到数据并不可以接收的数据;
其中三个接收部分,使用两个指针进行划分:
- RCV.WND:表示接收窗口的大小,它会通告给发送方。
- RCV.NXT:是一个指针,它指向期望从发送方发送来的下一个数据字节的序列号,也就是 #3 的第一个字节。
- 指向 #4 的第一个字节是个相对指针,它需要 RCV.NXT 指针加上 RCV.WND 大小的偏移量,就可以指向 #4 的第一个字节了。
⑨. 接收窗口和发送窗口的大小
二. 流量控制
- TCP 利用滑动窗口实现流量控制。流量控制是为了控制发送方发送速率,保证接收方来得及接收。 接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。
①. 流量控制
流量控制
- 客户端向服务端发送请求数据报文。这里是把服务端作为发送方。
- 服务端收到请求报文后,发送确认报文和 80 字节的数据,于是可用窗口 Usable 减少为 120 字节,同时 SND.NXT 指针也向右偏移 80 字节后,指向 321,这意味着下次发送数据的时候,序列号是 321。
- 客户端收到 80 字节数据后,于是接收窗口往右移动 80 字节,RCV.NXT 也就指向 321,这意味着客户端期望的下一个报文的序列号是 321,接着发送确认报文给服务端。
- 服务端再次发送了 120 字节数据,于是可用窗口耗尽为 0,服务端无法再继续发送数据。
- 客户端收到 120 字节的数据后,于是接收窗口往右移动 120 字节,RCV.NXT 也就指向 441,接着发送确认报文给服务端。
- 服务端收到对 80 字节数据的确认报文后,SND.UNA 指针往右偏移后指向 321,于是可用窗口 Usable 增大到 80。
- 服务端收到对 120 字节数据的确认报文后,SND.UNA 指针往右偏移后指向 441,于是可用窗口 Usable 增大到 200。
- 服务端可以继续发送了,于是发送了 160 字节的数据后,SND.NXT 指向 601,于是可用窗口 Usable 减少到 40。
- 客户端收到 160 字节后,接收窗口往右移动了 160 字节,RCV.NXT 也就是指向了 601,接着发送确认报文给服务端。
- 服务端收到对 160 字节数据的确认报文后,发送窗口往右移动了 160 字节,于是 SND.UNA 指针偏移了 160 后指向 601,可用窗口 Usable 也就增大至了 200。
②. 操作系统缓冲区与滑动窗口
- 客户端作为发送方,服务端作为接收方,发送窗口和接收窗口初始大小为 360;
- 服务端非常的繁忙,当收到客户端的数据时,应用层不能及时读取数据。
- 客户端发送 140 字节数据后,可用窗口变为 220 (360 - 140)。
- 服务端收到 140 字节数据,但是服务端非常繁忙,应用进程只读取了 40 个字节,还有 100 字节占用着缓冲区,于是接收窗口收缩到了 260 (360 - 100),最后发送确认信息时,将窗口大小通告给客户端。
- 客户端收到确认和窗口通告报文后,发送窗口减少为 260。
- 客户端发送 180 字节数据,此时可用窗口减少到 80。
- 服务端收到 180 字节数据,但是应用程序没有读取任何数据,这 180 字节直接就留在了缓冲区,于是接收窗口收缩到了 80 (260 - 180),并在发送确认信息时,通过窗口大小给客户端。
- 客户端收到确认和窗口通告报文后,发送窗口减少为 80。
- 客户端发送 80 字节数据后,可用窗口耗尽。
- 服务端收到 80 字节数据,但是应用程序依然没有读取任何数据,这 80 字节留在了缓冲区,于是接收窗口收缩到了 0,并在发送确认信息时,通过窗口大小给客户端。
- 客户端收到确认和窗口通告报文后,发送窗口减少为 0。
③. 收缩窗口、丢包的现象
- 客户端发送 140 字节的数据,于是可用窗口减少到了 220。
- 服务端因为现在非常的繁忙,操作系统于是就把接收缓存减少了 120 字节,当收到 140 字节数据后,又因为应用程序没有读取任何数据,所以 140 字节留在了缓冲区中,于是接收窗口大小从 360 收缩成了 100,最后发送确认信息时,通告窗口大小给对方。
- 此时客户端因为还没有收到服务端的通告窗口报文,所以不知道此时接收窗口收缩成了 100,客户端只会看自己的可用窗口还有 220,所以客户端就发送了 180 字节数据,于是可用窗口减少到 40。
- 服务端收到了 180 字节数据时,发现数据大小超过了接收窗口的大小,于是就把数据包丢失了。
- 客户端收到第 2 步时,服务端发送的确认报文和通告窗口报文,尝试减少发送窗口到 100,把窗口的右端向左收缩了 80,此时可用窗口的大小就会出现诡异的负值。
所以,如果发生了先减少缓存,再收缩窗口,就会出现丢包的现象。
- 为了防止这种情况发生,TCP 规定是不允许同时减少缓存又收缩窗口的,而是采用先收缩窗口,过段时间再减少缓存,这样就可以避免了丢包情况。
④. 窗口关闭
- 如果窗口大小为 0 时,就会阻止发送方给接收方传递数据,直到窗口变为非 0 为止,这就是窗口关闭。
- 那么,当发生窗口关闭时,接收方处理完数据后,会向发送方通告一个窗口非 0 的 ACK 报文,如果这个通告窗口的 ACK 报文在网络中丢失了,那麻烦就大了。
窗口关闭潜在的危险
- 这会导致发送方一直等待接收方的非 0 窗口通知,接收方也一直等待发送方的数据,如不采取措施,这种相互等待的过程,会造成了死锁的现象。
⑤. TCP 解决窗口关闭时,潜在的死锁现象
窗口探测
-
如果接收窗口仍然为 0,那么收到这个报文的一方就会重新启动持续计时器;
-
如果接收窗口不是 0,那么死锁的局面就可以被打破了。
-
窗口探测的次数一般为 3 次,每次大约 30-60 秒(不同的实现可能会不一样)。如果 3 次过后接收窗口还是 0 的话,有的 TCP 实现就会发 RST 报文来中断连接。
⑥. 糊涂窗口综合症
-
如果接收方太忙了,来不及取走接收窗口里的数据,那么就会导致发送方的发送窗口越来越小。
-
到最后,如果接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,这就是糊涂窗口综合症。
-
接收方的窗口大小是 360 字节,但接收方由于某些原因陷入困境,假设接收方的应用层读取的能力如下:
-
接收方每接收 3 个字节,应用程序就只能从缓冲区中读取 1 个字节的数据;(读取三分之一)
-
在下一个发送方的 TCP 段到达之前,应用程序还从缓冲区中读取了 40 个额外的字节;
⑦. 解决糊涂窗口综合症方法
- 让接收方不通告小窗口给发送方
- 让发送方避免发送小数据
让接收方不通告小窗口
让发送方避免发送小数据
这篇关于TCP传输协议---滑动窗口、流量控制的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!