本文提纲
重传机制
TCP针对数据包丢失的情况,采用重传机制
解决
常见的重传机制:
- 超时重传
- 快速重传
- SACK
- D-SACK
超时重传
超时重传:当发送数据时,设立一个定时器,当超过指定时间后,发送端没有收到ACK应答报文,则触发
超时重传
机制,重发该数据
超时时间设置为多少呢?也就是超时重传时间RTO
假设我们设置的超时重传时间过短的话,那么就很有可能造成我们数据包还没到接收端或者应答ACK没到发送方就会重传:
假设我们设置超时时间过长的话,那么就会导致数据包丢失了一段花时间,我们才重传,减低了我们网络传输效率:
所以超时时间就应该设置为一个适中的值,那拿什么作为标准呢?
首先我们清楚一个RTT(往返时延) 的概念
所以我们的超时时间RTO的值应该略大于报文往返 RTT 的值
因为我们的网络是经常变化的,所以我们RTT报文往返时延也会动态变化,RTO时间也会动态变化
定时器过期很可能是由网络拥塞引起的,在拥塞的时候,如果发送端持续重传分组,会使得拥塞越来越严重。相反,TCP采用的是发送端每次的重传都是经过越来越长的时间进行的。每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。
超时重传存在的问题之一就是超时周期过长,当我们多次丢失数据包时,这种长周期的机制就会使我们延迟发送,加大了端到端的时延
快速重传
为了解决这种长周期情况,TCP通常可在超时时间发生之前通过冗余的ACK
来较好的检测丢包情况
因为发送方经常一个接一个地发送大量的报文段,如果一个报文段丢失,就很可能引起许多一个接一个的冗余ACK,如果TCP发送方接收到对相同数据的3个冗余ACK,它 把这当作一种指示,说明跟在这个已被确认过3次的报文段之后的报文段已经丢失.一旦收到3个冗余ACK, TCP就执行快速重传(fast retransmit) [RFC 5681 ],即 在该报文段的定时器过期之前重传丢失的报文段
事件:收到ACK,具有ACK字段值y
if (y > SendBase) {
SendBase=y
if (当前仍无任何应答报文段)启动定时器 }
else {/★对已经确认的报文段的一个冗余ACK */
对y收到的冗余ACK数加1
if (对y==3收到的冗余ACK数)
/* TCP快速重传*/
重新发送具有序号y的报文段
}
break;
快速重传机制只解决了一个问题,就是超时时间的问题,但是它依然面临着另外一个问题。就是重传的时候,是
重传之前的一个,还是重传所有
的问题。
SACK
针对上述情况,改进的方法就是 SACK(Selective Acknowledgment)
,这种方式需要在 TCP 头部「选项」字段里加一个 SACK 的东西,简单来讲就是在快速重传的基础上,返回最近收到的报文段的序列号范围,这样客户端就知道,哪些数据包已经到达服务器了。
如上图,发送方收到了三次同样的 ACK 确认报文,于是就会触发快速重发机制,通过 SACK 信息发现只有 200~299 这段数据丢失,则重发时,就只选择了这个 TCP 段进行重复。
Duplicate SACK
DSACK
,即重复 SACK,这个机制是在 SACK 的基础上,额外携带信息,告知发送方有哪些数据包自己重复接收了。DSACK 的目的是帮助发送方判断,是否发生了包失序、ACK 丢失、包重复或伪重传。让 TCP 可以更好的做网络流控
。