TCP的差错控制主要使用校验和
、确认
、超时重传
这三个工具进行差错控制。
校验和主要用来检验数据报文是否受到损伤。如果校验和无效,报文就会在终点被丢弃。
确认是接收端用来证实确实收到了报文,在TCP中,使用的是累计确认,接收端会告诉发送端其下一个希望接收的字节编号。
超时重传是差错控制的核心。实际上当发送端发送一段字节的数据后,会把这个报文段保存在一个队列中,并启动一个计时器,这个计时器也叫RTO(重传计时器),若计时器超时发送端还没有收到接收端的ACK确认,那么发送端会把队列中的首部报文重新发送。
当然RTO的值是动态的,与RTT有关,RTT是一个报文自发送到接收端返回确认的时间。如果RTO的值不是很大。使用简单的超时重传也就够了,但是如果RTO的值足够大,再使用超时重传就不太切实际了。
TCP是这样处理的:如果发送端连续收到三个重复的超时重传ACK,那么发送端可以不必等待计时器到达而选择马上重传报文段,这种机制也称为快重传
。
还有一点要注意的是:接收端接收的数据可能不是按序到达的,当接收到不是按序到达的数据的时候,接收端不会丢弃该数据,而是先保存起来,并立即发送一个ACK,当其他失序的报文都到达后才把数据交付给接收进程。由于当RTO的值比较大的时候,TCP会采用快重传机制重传丢失的报文段,所以当发送完一个报文段后,如果发送端连续接收到3个重复的ACK确认的时候就会马上重传报文段,即使RTO计时器还没有超时。下图是快重传的一个流程图:
针对这个流程图说明快重传的机制:
- 当发送端收到接收端ackNo=301的报文的时候,继续传输起始编号为301长度为100字节的数据,但是这个报文段丢失了,而发送端继续传输了字节编号从401到500的字节,接收端于是收到了失序但无差错的报文段,接收端把这段报文保存起来,并在接收窗口隔一个空隙,表示还有失序的报文没有到达,并给发送端发送ackNo=301的报文,表示起始编号为301的字节数据我这边还没有收到,你那边注意一下,准备重传吧
- 发送端收到这个报文后,仍然继续传输起始编号为501到600的字节,接收端接收到后保存起来,并重新发送ackNo=301的报文
- 发送端继续发送起始编号为601到700的字节,接收端收到后保存起来,并再次发送ackNo=301得的报文,由于这已经是第四次收到重复的ACK确认了,虽然这时RTO计时器还没有到达,但是发送端立即发送起始编号为301的字节数据。