一般来说,我们总是希望数据传输得更快一些。
- 但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。
所谓流量控制(flow control)就是 让发送方的发送速率不要太快,要让接收方来得及接收 \color{red}让发送方的发送速率不要太快,要让接收方来得及接收 让发送方的发送速率不要太快,要让接收方来得及接收。
利用
滑动窗口
\color{red}滑动窗口
滑动窗口机制可以很方便地在 TCP
连接上实现对发送方的流量控制。
1、A、B建立TCP连接
假设主机 A
和 B
是因特网上的两台主机
它们之间已经建立了 TCP
连接,A
给 B
发送数据,B
对 A
进行流量控制
这是主机 A
中待发送数据的字节序号
假设主机 A
发送的每个 TCP
数据报文段可携带
100
100
100 字节数据
- 因此图中每个小格子表示 100 100 100 个字节数据的序号
在主机 A
和 B
建立 TCP
连接时,B
告诉 A
:“我的接收窗口为 400”
- 因此,主机
A
将自己的发送窗口也设置为 400 400 400
这意味着主机 A
在未收到主机 B
发来的确认时,可将序号落入发送窗口中的全部数据发送出去
2、A发送TCP报文段
主机A对B的流量控制
主机 A
将发送窗口内序号
1
1
1 ~
100
100
100 的数据封装成一个 TCP
报文段发送出去
- 发送窗口内还有 300 300 300 字节可以发送
这里的 seq
是 TCP
报文段首部中的序号字段
- 取值
1
1
1 表示
TCP
报文段数据载荷的第一个字节的序号是 1 1 1
这列的 data
表示这是 TCP
数据报文段
主机 A
将发送窗口内序号
101
101
101 ~
200
200
200 的数据封装成一个 TCP
报文段发送出去
- 发送窗口内还有 200 200 200 字节可以发送
主机 A
将发送窗口内序号
201
201
201 ~
300
300
300 的数据封装成一个 TCP
报文段发送出去
-
但该报文段在传输过程中 丢失 \color{red}丢失 丢失了
-
发送窗口内还有 100 100 100 字节可以发送
3、B对A的累计确认并进行第一次流控
主机 B
对主机 A
所发送的
201
201
201 号以前的数据进行
累计确认
\color{red}累计确认
累计确认
并在该累计确认中将窗口字段的值调整为
300
300
300 ,对主机 A
进行流控
这里的大写 ACK
是 TCP
报文段首部中的
标志位
\color{blue}标志位
标志位
- 取值
1
1
1 表示这是一个
TCP
确认报文段
小写 ack
是 TCP
报文段首部中的
确认号字段
\color{blue}确认号字段
确认号字段
-
取值 201 201 201 表示序号 201 201 201 之前的数据已全部正确接收
-
现在希望收到序号 201 201 201 及其后续数据
rwnd
是 TCP
报文段首部中的
窗口字段
\color{blue}窗口字段
窗口字段
- 取值 300 300 300 表示自己的接收窗口大小为 300 300 300
4、A发送TCP报文段但丢失了
主机 A
收到该累计确认后,将发送窗口向前滑动
- 使已发送并受到确认的这些数据的序号
移出
发送窗口
由于主机 B
在该累计确认中将自己的接收窗口调整为了
300
300
300
- 因此,主机
A
相应的将自己的发送窗口调整为 300 300 300
目前,主机 A
发送窗口内的序号为
201
201
201 ~
500
500
500
也就是主机 A
还可以发送这
300
300
300 字节
- 其中 201 201 201 ~ 300 300 300 字节是已发送的数据
- 若重传计时器超时,它们会被重传
301 301 301 ~ 400 400 400 号字节以及 401 401 401 ~ 500 500 500 号字节还未被发送
- 可被分别封装在一个
TCP
报文段中发送
主机 A
现在可将发送缓存中序号
1
1
1 ~
200
200
200 的字节数据全部删除了
- 因为已经收到了主机
B
对它们的累计确认
主机 A
将发送窗口内序号
301
301
301 ~
400
400
400 的数据封装成一个 TCP
报文段发送出去
- 发送窗口内还有 100 100 100 字节可以发送
主机 A
将发送窗口内序号
401
401
401 ~
500
500
500 的数据封装成一个 TCP
报文段发送出去
- 至此,序号落在发送窗口内的数据已经全部发送出去了, 不能发送新数据了 \color{red}不能发送新数据了 不能发送新数据了
现在,发送窗口内序号
201
201
201 ~
300
300
300 这
100
100
100 个字节数据的重传计时器超时了
主机 A
将他们重新封装成一个 TCP
报文段发送出去
5、B对A的累计确认并进行第二次流控
主机 B
收到该重传的 TCP
报文段后,对主机 A
所发送的
501
501
501 号以前的数据进行累计确认
- 并在该累计确认中将窗口字段的值调整为 100 100 100
这是主机 B
对主机 A
进行的第二次流量控制
主机 A
收到该累计确认后,将发送窗口向前滑动
- 使已发送并受到确认的这些数据的序号移出发送窗口
由于主机 B
在该累计确认中将自己的接收窗口调整为了
100
100
100
- 因此,主机
A
相应的将自己的发送窗口调整为 100 100 100
目前,主机 A
发送窗口内的序号为
501
501
501 ~
600
600
600
也就是主机 A
还可以发送这
100
100
100 字节
主机 A现在可将发送缓存中序号 201 201 201 ~ 500 500 500 的字节数据全部删除了
- 因为已经收到了主机
B
对它们的累计确认
6、A发送TCP报文段
主机 A
将发送窗口内序号
501
501
501 ~
600
600
600 的数据封装成一个 TCP
报文段发送出去
- 至此,序号落在发送窗口内的数据已经全部发送出去了, 不能发送新数据了 \color{red}不能发送新数据了 不能发送新数据了
7、B对A的累计确认并进行第三次流控
主机 B
收到该重传的 TCP
报文段后,对主机 A
所发送的
601
601
601 号以前的数据进行累计确认
- 并在该累计确认中将窗口字段的值调整为 0 0 0
这是主机 B
对主机 A
进行的第三次流量控制
主机 A
收到该累计确认后,将发送窗口向前滑动
- 使已发送并受到确认的这些数据的序号移出发送窗口
由于主机 B
在该累计确认中将自己的接收窗口调整为了
0
0
0
- 因此,主机
A
相应的将自己的发送窗口调整为 0 0 0
目前主机 A
不能再发送一般的 TCP
报文段了
主机 A
现在可将发送缓存中序号
501
501
501 ~
600
600
600 的字节数据全部删除了
- 因为已经收到了主机
B
对它们的累计确认
8、TCP 死锁问题
假设主机 B
向主机 A
发送了零窗口的报文段后不久,主机 B
的接收缓存又有了一些存储空间
- 于是,主机
B
向主机A
发送了接收窗口等于 300 300 300 的报文段
然而,这个报文段再传输过程中丢失了,主机 A
一直等待主机 B
发送的非零窗口的通知
- 而主机
B
也一直等待A
发送的数据
如果不采取措施,这种互相等待而形成的死锁局将一致持续下去
为了解决这个问题,TCP
为每一个连接设置了一个
持续计时器
\color{red}持续计时器
持续计时器
- 只要
TCP
连接的一方收到对方的零窗口通知,就启动
持续计时器
若持续计时器超时,就发送一个 零窗口探测报文 \color{red}零窗口探测报文 零窗口探测报文,仅携带 1 1 1 字节的数据
而对方在确认这个探测报文段时,给出自己现在的接收窗口值
-
若接收窗口仍然是 0 0 0,那么收到这个报文段的一方就
重新启动
持续计时器 -
若接收窗口不是 0 0 0,那么死锁的局面就可以被打破了
在本例中,主机 A
收到零窗口通知时,就启动一个持续计时器
- 当持续计时器超时,主机
A
立刻发送一个仅携带 1 1 1 字节数据的零窗口探测报文段
假设主机 B
此时的接收窗口又为
0
0
0 了
- 主机
B
就在确认这个零窗口探测报文段时,给出自己现在的接受窗口值为 0 0 0
主机 A
再次收到零窗口通知,就再次启动一个持续计时器
- 当持续计时器超时,主机
A
立刻发送一个仅携带 1 1 1 字节数据的零窗口探测报文段
假设主机 B
此时的接收缓存又有了一些存储空间
- 于是将自己的接收窗口调整为了 300 300 300
主机 B
就在确认这个零窗口探测报文段时,给出自己现在的接受窗口值为
300
300
300
这样就打破了死锁的局面
若主机 A
发送的零窗口探测报文段到达主机 B
时
-
若主机
B
此时的接收窗口仍然为 0 0 0那么主机
B
根本就无法接收该报文段 -
又怎么会针对该报文段给主机
A
发回确认呢?
实际上,TCP
规定即使接收窗口为
0
0
0 也必须接受
- 零窗口探测报文段 \color{blue}零窗口探测报文段 零窗口探测报文段、 确认报文段 \color{blue}确认报文段 确认报文段、以及 携带有紧急数据的报文段 \color{blue}携带有紧急数据的报文段 携带有紧急数据的报文段
若零窗口探测报文段丢失了,会出现怎样的问题呢?还能否打破死锁的局面么?
- 肯定的
因为零窗口探测报文段也有重传计时器
- 当重传计时器超时后,零窗口探测报文段会被重传
9、习题
在上述的举例中,为了简单起见,忽略了拥塞控制
- 也就是认为
TCP
发送放的发送窗口等于
接收方的接受窗口
确认多少,滑动窗口就滑动多少