2 TCP可靠传输
目录- 可靠性和流量控制由滑动窗口协议保证
- 链路拥塞则由拥塞控制的算法实现
TCP的精髓:滑动窗口协议
1. 滑动窗口协议(依据接收方返回的ack拓展滑动窗口)
-
“窗口”:对应一段可以被发送者发送的字节序列,其连续的范围称之为“窗口”
-
“滑动”:指这段“允许发送的范围”是随着发送的过程而按顺序“滑动”的
-
了解一下协议的前提:
- TCP全双工,A发有发送缓冲区,B收有接收缓冲区。
- 发送窗口是发送缓冲区的一部分,是可以被发送的部分。其实应用层需要发送的所有数据都被放进了发送者的发送缓冲区。每次发送成功后,发送窗口就会在发送缓冲区内按顺序移动,将新数据包含到发送窗口内准备发送。
- 发送窗口相关的四个概念:
- 已发送并收到确认的数据(不在发送缓冲区内;同样也不会在接收缓冲区内)
- 已发送但未收到确认的数据(在发送窗口内)
- 允许发送但未发送的数据(在发送窗口内)
- 暂时不允许发送的数据(不在发送窗口内,但在缓冲区内)
-
协议例子描述:
-
TCP建立连接的初始,B会告诉A自己的接收窗口大小,比如为‘20’:
-
A发送11个字节后,发送窗口位置不变,B接收到了乱序的数据分组:
-
只有当A成功发送了数据,即发送的数据得到了B的确认之后,才会移动滑动窗口离开已发送的数据;同时B则确认连续的数据分组,对于乱序的分组则先接收下来,避免网络重复传递:
-
2. 流量控制(防止丢包):
- 流量控制,指B回传自己的接收窗口给A,让A不要发的太快,是一种端到端控制。
- B返回的ACK中包含接收窗口rwnd,并且利用其大小控制A的发送
可能存在的问题:新生缓冲死锁
- rwnd接收窗口为0时,也就是B告诉A接收缓冲区已满,于是A停止发送数据。
- 等待一段时间后,B接收缓冲区出现富余,按理说于是给A发报文说rwnd为400。
- 但报文丢了,于是出现 A等待B的通知 || B等待A发送数据 的死锁状态。
解决方案:TCP引入了持续计时器(Persistence timer),当A收到对方的零窗口通知时,就启用该计时器,时间到则发送一个1字节的探测报文,对方会在此时回应自身的接收窗口大小,如果结果仍未0,则重设持续计时器,继续等待。
3. 传递效率
- 问题:如果单个字节发送单个确认,或者接收窗口有一个空余即通知发送方发送一个字节,无疑增加了网络中许多不必要的报文(请想想为了一个字节数据而添加的40字节头部吧!)。
- 解决方案:
- 思想:批发批收,减少链路中网络包数量,防止网络过载
- 尽可能一次多发送几个字节(Nagle算法)
- 窗口空余较多的时候才通知发送方一次发送多个字节,也就是让接收方等待一段实践,或者接收方获得足够的空间容纳一个报文或者等到接收缓存有一半空闲时,再通知发送方发送数据。(防止糊涂窗口综合症)
Nagle算法(表象):
为了尽可能发送大块数据,避免网络中充斥着许多小数据块。
- 若进程要把数据逐个字节地送到TCP的发送缓存,则A就把第一个数据字节先发送出去,后面的字节先缓存起来;
- 当A收到第一个字节的确认后(得到了网络情况和对方的接收窗口大小),再把缓冲区的剩余字节组成合适大小的报文发送出去;(等待ACK,然后才发下一个)
- 当到达的数据已达到发送窗口大小的一半或以达到报文段的最大长度时,就立即发送一个报文段;(不等ACK,还有一种就是紧急指针)
糊涂窗口综合症(silly window syndrome)设想一种情况:TCP接收方的缓存已满,而交互式的应用进程一次只从接受缓存中读取一个字节(这样接收缓存空间就仅腾出一个字节),然后向发送方发送确认,并把窗口设置为一个字节(但发送的数据报是40字节长)。接着,发送方又发来一个字节的数据(此时发送方发送的IP数据报是41字节长)。接收方发回确认,如此进行下去,是网络效率很低。
-
另一个提高效率机制:ACK延迟机制
- B收到数据,不会马上回复ACK,而是会延迟一段时间。因为B希望这段时间内B会向A发送应答数据,这样ACK就能和应答数据一起发过去。(两个请求 --> 一个请求),这也是为什么我们看到ACK一般都跟ack、rwnd在一起发
-
Nagle算法本质:
防止链路加塞的精髓:拥塞控制
问题:网络中的链路容量和交换结点中的缓存和处理机都有着工作的极限,当网络的需求超过它们的工作极限时,就出现了拥塞。
解决:拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
-
拥塞控制的相关概念:
- cwnd(congestion window)是一个发送方维护的一个状态变量,他会根据网络的拥塞程度动态变化。
- swnd = min(cwnd, rwnd),也就是发送窗口是拥塞窗口和接收窗口中的最小值。
-
如何知道网络中是否发生了拥塞
- 其实只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传(快速重传),就会认为网络出现了拥塞。
-
拥塞控制算法简介
- 拥塞控制的过程分为四个阶段:慢启动、拥塞避免、拥塞发生(快重传),快恢复。
- 这个图略微不对,TD时cwnd = cwnd/2 ,ssthresh = cwnd。
慢启动算法+拥塞避免算法(TCP Tahoe版本,已废弃): 1. 发送方维持一个叫做“拥塞窗口”的变量,该变量和接收端口共同决定了发送者的发送窗口; 2. 当主机开始发送数据时,避免一下子将大量字节注入到网络,造成或者增加拥塞,选择发送一个1字节的试探报文; 3. 当收到第一个字节的数据的确认后,就发送2个字节的报文; 4. 若再次收到2个字节的确认,则发送4个字节,依次递增2的指数级; 5. 最后会达到一个提前预设的“慢开始门限”,比如24,即一次发送了24个分组,此时遵循下面的条件判定: 1. cwnd < ssthresh, 继续使用慢开始算法; 2. cwnd > ssthresh,停止使用慢开始算法,改用拥塞避免算法; 3. cwnd = ssthresh,既可以使用慢开始算法,也可以使用拥塞避免算法; 6. 所谓拥塞避免算法就是:每经过一个*往返时间RTT*就把发送方的拥塞窗口+1,即让拥塞窗口缓慢地增大,按照线性规律增长; 7. 当出现网络拥塞,比如丢包时,将慢开始门限设为原先的一半,然后将cwnd设为1,执行慢开始算法(较低的起点,指数级增长);
慢启动+拥塞避免+拥塞发生(快重传)+快恢复(TCP Reno版本): 1. 「快速重传算法」。当接收方发现丢了一个中间包的时候,发送三次前一个包的 ACK,于是发送端就会快速地重传,不必等待超时再重传。 TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,ssthresh 和 cwnd 变化如下: cwnd = cwnd/2 ,也就是设置为原来的一半; ssthresh = cwnd;进入快速恢复算法; 2. 快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕。 正如前面所说,进入快速恢复之前,cwnd 和 ssthresh 已被更新了: cwnd = cwnd/2 ,也就是设置为原来的一半; ssthresh = cwnd; *1.不执行慢开始算法(即拥塞窗口cwnd现在不设置为1),而是把cwnd值设置为自身减半后的数值 *2.然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大
- 这两张图,是不同版本的实现。
标签:窗口,字节,TCP,可靠,发送,传输,拥塞,cwnd From: https://www.cnblogs.com/iterationjia/p/17064061.html有的快重传实现是把开始时的拥塞窗口cwnd值再增大一点,即拥塞窗口
cwnd = ssthresh + 3
( 3 的意思是确认有 3 个数据包被收到了)。这样做的理由是:既然发送方收到三个重复的确认,就表明有三个分组已经离开了网络。这三个分组不再消耗网络 的资源而是停留在接收方的缓存中。可见现在网络中并不是堆积了分组而是减少了三个分组。因此可以适当把拥塞窗口扩大了些。