1. 概述
- tcp提供可靠的运输层,使用的方法是确认机制。
- 但是数据和确认都有可能丢失
- tcp通过在发送时设置定时器解决这种问题
- 定时器时间到了还没收到确认,就重传该数据
2. tcp管理的定时器类型
- 重传定时器:等待收到确认
- 坚持定时器:使窗口大小信息保持不断流动
- 保活定时器:检测空闲连接崩溃或重启
- 2MSL定时器:检测time_wait状态
3. 超时重传机制
3.1 背景
- 接收端给发送端的Ack确认只会确认最后一个连续的包
- 比如发送1,2,3,4,5共五份数据,接收端收到1,2,于是回ack3,然后收到4(还没收到3),此时tcp不会跳过3直接确认4,否则发送端以为3也收到了。这时你能想到的方法是什么呢?tcp又是怎么处理的呢?
3.1 被动等待的超时重传策略
- 直观的方法是:接收方不做任何处理,等待发送方超时,然后重传。
- 缺点:发送端不知道该重发3,还是重发3,4,5
- 如果发送方如果只发送3:节省宽度,但是慢
- 如果发送方如果发送3,4,5:快,但是浪费宽带
- 总之,都在被动等待超时,超时可能很长。所以tcp不采用此方法
3.2 主动的快速重传机制
3.2.1 概述
- 名称为:Fast Retransmit
- 不以实际驱动,而以数据驱动重传
3.2.2 实现原理
- 如果包没有送达,就一直ack最后那个可能被丢的包
- 发送方连续收到3相同的ack,就重传。不用等待超时
- 图中发生1,2,3,4,5数据
- 数据1到达,发生ack2
- 数据2因为某些原因没有送到
- 后续收到3的时候,接收端并不是ack4,也不是等待。而是主动ack2
- 收到4,5同理,一直主动ack2
- 客户端收到三次ack2,就重传2
- 2收到后,结合之前收到的3,4,5,直接ack6
3.2.3 快速重传的利弊
- 解决了被动等待timeout的问题
- 无法解决重传之前的一个,还是所有的问题。
- 上面的例子中是重传2,还是重传2,3,4,5。因为并不清楚ack2是谁传回来的
3.3 SACK方法
3.3.1 概述
- 为了解决快速重传的缺点,一种更好的SACK重传策略被提出
- 基于快速重传,同时在tcp头里加了一个SACK的东西
- 解决了什么问题:客户端应该发送哪些超时包的问题
3.3.2 实现原理
- SACK记录一个数值范围,表示哪些数据收到了
- linux2.4后默认打开该功能,之前版本需要配置tcp-sack参数
- SACK只是一种辅助的方式,发送方不能完全依赖SACK。主要还是依赖ACK和timout
3.3.3 Duplicate SACK(D-SACK)
- 使用SACK标识的范围,还可以知道告知发送方,有哪些数据被重复接收了
- 可以让发送方知道:是发出去的包丢了,还是回来的ack包丢了
4. 超时时间的确定
4.1 背景
- 路由器和网络流量均会变化
- 所以超时时间肯定不能设置为一个固定值
- 超时长:重发慢,效率低,性能差
- 超时短:并没有丢就重发,导致网络拥塞,导致更多超时和更多重发
- tcp会追踪这些变化,并相应的动态改变超时时间(RTO)
4.2 如何动态改变
- 每次重传的时间间隔为上次的一倍,直到最大间隔为64s,称为“指数退避”
- 首次重传到最后放弃重传的时间间隔一般为9min
- 依赖以往的往返时间计算(RTT)动态的计算
4.3 往返时间(RTT)的计算方法
- 并不是简单的ack时间和发送时间的差值。因为有重传,网络阻塞等各种变化的因素。
- 而是通过采样多次数值,然后做估算
- tcp使用的方法有:
- 被平滑的RTT估计器
- 被平滑的均值偏差估计器
4.4. 重传时间的具体计算
- 计算往返时间(RTT),保存测量结果
- 通过测量结果维护一个被平滑的RTT估计器和被平滑的均值偏差估计器
- 根据这两个估计器计算下一次重传时间
5. 超时重传引发的问题-拥塞
5.1 为什么重传会引发拥塞
- 当网络延迟突然增加时,tcp会重传数据
- 但是过多的重传会导致网络负担加重,从而导致更大的延时和丢包,进入恶性循环
- 也就是tcp的拥塞问题
5.2 解决拥塞-拥塞控制的算法
- 慢启动:降低分组进入网络的传输速率
- 拥塞避免:处理丢失分组的算法
- 快速重传
- 快速恢复
作者:kinnylee 链接:https://juejin.im/post/5ba895a06fb9a05ce95c5dac 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。