TCP接收端返回发送端的一系列确认信息来判断是否出现丢包,当数据包和确认信息丢失,TCP则启动重传操作。TCP拥有两套独立的机制来完成重传。一个是基于时间一个是基于确认信息构成的。
- 针对超时做出的处理:快速重传,超时重传RTO
- 针对丢失做出的处理:选择确认
超时重传
- A发送报文,B完整的收到数据并返回ACK,但是由于某种原因丢失,当超时事件发生,A会重新发送数据,B由于接收过数据,会将重传的报文段丢弃并且返回对应ACK
- A发送两段报文,,B接收到后为每个报文发送对应的ACK。超时发生前,两个ACK没有到A,当超时时间发生。A会重传第一个报文。只要第二个ACK在新的超时发生前到达,就不会被重传。
大多数情况下计时器超时并触发重传是不必要的,因为RTO设置的值通常大于RTT(约2倍以上),超时重传会导致网络利用率下降。
快速重传
快速重传跟超时重传相比,更能有及时的修复丢包情况, 当时有失序报文被接受到的时候,TCP立刻生成确认信息(重复的ACK), 当TCP等到一定数目的重复ACK,来决定数据是否丢失并触发快速重传。默认阈值是3次。
当不使用SACK的时候,在接收到有效的ACK前至多只能重传一个报文段。由于数据包2丢失,导致3,4,5返回的ACK都是重复的,接收端并不知道返回的ACK是是接收端谁发的,所以会重新再发送2,3,4,5..虽然TCP协议是累计确认,但是仍造成不必要的包发送了。
选择确认 SACK (Selective Acknowledgment)
为了解决一个RTT可能有多个空缺和尽可能的保证不重传正确接受的数据,引入了SACK. 这种方式是在TCP头的可选项里增加SACK,SACK包含已接收成功但由于非连续而未被确认的数据段的序列号范围列表。这样发送端就可以根据回传的SACK知道哪些数据到达了。哪些没有,这个协议需要接收方和发送方都要支持。
重复选择确认 D-SACK
很多情况下没有出现数据丢失也会出现重传,是因为过早的判定超时导致的。引入D-SACK ,主要用于告诉发送方有哪些数据被重复接受了。
D-SACK使用了SACK的第一个段来做标志, * 如果SACK的第一个段的范围被ACK所覆盖,那么就是D-SACK * 如果SACK的第一个段的范围被SACK的第二个段覆盖,那么就是D-SACK
发送重复数据
1
2
3
4
5
Transmitted Received ACK Sent
Segment Segment (Including SACK Blocks)
3000-3499 3000-3499 3500 (ACK dropped)
3500-3999 3500-3999 4000 (ACK dropped)
3000-3499 3000-3499 4000, SACK=3000-3500
接收端丢失了几个ACK包,发送端重新发送数据包(3000-3499) ,接收端发现是重复接受,由于累计确认 则返回ACK 4000 并且SACK 标记成3000-3500 ,说明这个包其实之前是已经接受到了,只不过是ACK 丢失。
无序和重复的数据
1
2
3
4
5
6
7
Transmitted Received ACK Sent
Segment Segment (Including SACK Blocks)
3000-3499 3000-3499 3500 (ACK dropped)
3500-3999 3500-3999 4000 (ACK dropped)
4000-4499 (data packet dropped)
4500-4999 4500-4999 4000, SACK=4500-5000 (ACK dropped)
3000-3499 3000-3499 4000, SACK=3000-3500, 4500-5000
接收端丢失了几个ACK包,并且有个数据包(4000-4499) 没有发送成功。再新的的数据包(4500-4999 )发送后,接收端返回最后一次收到的ACK,但是返回的ACK依旧丢失了。最后数据包(3000-3499)重传,因为累计确认,接收端返回ACK4000,SACK=3000-3500, 4500-5000意思是 3000-3500之前接受过,只不过是ACK丢失,4500-5000也已经被接收到。后续如果 继续重新发送数据包应该是
1
4000-4499 4000-4499 5000, SACK = 4500-5000
网络延时
1
2
3
4
5
6
7
8
9
10
Transmitted Received ACK Sent
Segment Segment (Including SACK Blocks)
500-999 500-999 1000
1000-1499 (delayed)
1500-1999 1500-1999 1000, SACK=1500-2000
2000-2499 2000-2499 1000, SACK=1500-2500
2500-2999 2500-2999 1000, SACK=1500-3000
1000-1499 1000-1499 3000
1000-1499 3000, SACK=1000-1500
---------
数据包(1000-1499 )由于网络延时没有收到ACK,等到重新发送的时候,接收端ACK已经返回3000,所以SACK=1000-1500 说明之前已经接受到了,只不过是ACK丢失而已