快重传为什么是3次冗余ACK触发?后来的TCP有什么变化?SACK是什么?
reno算法
即在三次冗余ACK(第四个相同的ACK)的时候触发重传, 重置计时器。 在重传的包的ACK返回的时候回到拥塞避免阶段。
为什么是3次冗余ACK呢? 是工程相关的问题。 首先不能太多,太多那不如等计时器超时重传。 也不能太少, 原因是包逆序了也会造成冗余ACK,但是我们想要捕捉的是丢包的情况。
new reno算法
Reno快速恢复算法中发送方收到一个新的ACK就退出快速恢复状态,New Reno算法中只有当所有报文都被应答后才退出快速恢复状态。使TCP终端可以把一次拥塞丢失多个报文的情形与多次拥塞的情形区分开来,进而在每一次拥塞发生后拥塞窗口仅减半一次,从而提高了TCP的顽健性和吞吐量。
reno算法在一次性丢好几个包的时候很可能造成反复的减半ssthresh 和拥塞窗口。 造成拥塞窗口大幅度减小, 最极端的情况下会减小到三个一下,无法再产生三个冗余ACK触发new reno,那就只能等待超时重传。
new reno旨在解决这个问题。 主要通过定义并且延长了快速恢复阶段。
PACK和RACK
在三个冗余ACK到达,触发reno算法的时候, 发送端也会记录自己已经发送过的最大SYN
PACK : 部分ACK,当返回的ACK < SYN_MAX + 1
RACK:全部ACK,当返回的ACK == SYN_MAX + 1
只有收到全部ACK的时候才重新进入拥塞避免阶段。
一个简单的例子,如果发包1-20,然后4,5,6,丢失。 7,8,9,10到了,发送端收到4个ack4, 触发reno算法,缩减拥塞窗口, 重传4成功, 然后10之后的包陆续到,发送端收到4个ACK 5,又触发reno算法, 又一次缩减拥塞窗口, 6还要再触发一次reno算法,再缩减一次拥塞窗口。 那我们实际上为了一次丢包(只不过是成组的),拥塞窗口变成了原来的1/8。
但是有了new reno之后,发送端收到4个ack4, 触发new reno算法,缩减拥塞窗口, 记录自己发送过的最大SYN=20, 从第一个RTT开始依次重传4,ack 4, 重传5, ack 5,重传6, ack6 ,这会儿11-20的对应ACK到了。 那么ACK21作为RACK,结束快速恢复的过程。 回到拥塞避免。 这样, 拥塞窗口之缩减了一次。
实际上new reno的拥塞窗口计算也不是简单减半,而是基于prr 算法 [RFC6937],主要能有以下两个特征
-
在快速恢复过程中,拥塞窗口非常平滑地向 ssthresh 收敛
-
在快速恢复结束后,拥塞窗口处在 ssthresh 附近
具体计算看
zhuanlan.zhihu.com/p/144273871
SACK
new reno算法仍然不能解决的是, 重传的时候到底重传哪些包合适。 传少了恢复慢,传多了是在本来给拥塞的网络添加不必要的负载。 根本的原因是发送端不知道哪些包丢了。 比如说上面的例子, 发送端只是受到4个ack4(即三个针对4的冗余ACK),“4,5,6”丢包这个信息接收端知道, 但是没有办法通过现在的ACK的方式告诉发送端。
SACK, 选择ACK,就是这样的机制。 它允许在ACK信息后面加入新的SACK信息,告诉发送端自己都接收到了哪些信息。 发送端在自己发送出去的所有数据比对,很容易就得到哪些数据没有收到,那么就只重传这些信息。
值得一提的是, 是否使用SACK机制是TCP在三次握手里的前两次里决定的。 双方交流自己是否支持SACK机制,都支持才启用这个机制。
这样,在丢包的时候,就可以针对性地,批量地重发丢了的包,在new reno的基础上, 优势就是在快速恢复的时候, 每个RTT可以批量重传没接到的一组包(英文叫hole)