什么是 TCP 的超时重传?
我们先回顾一下 TCP 的三个特点:面向连接、可靠、基于字节流,那么 TCP 的可靠传输是如何实现的呢?超时重传机制就是保证 TCP 可靠传输的一种手段。
超时重传能确保数据在传输过程中,即使因为丢包、网络延迟或其他原因导致数据包没有成功到达接收方,依然能够重新发送,从而实现可靠的数据传输。通俗来讲,超时重传就是发送方在发送数据后,会等待接收方的确认(回传的 ACK 报文)。如果没有在规定的时间内收到确认,就会重新发送数据包。
注意:ACK 报文是不会重传的。
超时重传的基本原理
每次发送一个数据包时,发送方都会设置一个定时器,该定时器会在一定的时间内等待接收方的 ACK 确认。如果定时器超时之前收到了 ACK ,则说明数据包成功到达接收方,TCP 连接继续进行。如果定时器到期了仍然没有收到 ACK ,则认为数据包丢失或者未达到接收方,发送方就会重新发送该数据包,这就是超时重传机制的基本原理。
如果发送方一直没有收到 ACK 确认,就会继续重发报文。但是一直重发也不行,因此在 Linux 中有一个 TCP 参数控制重传次数:tcp_orphan_retries
。当发送方重传报文的次数超过 tcp_orphan_retries
后,就不再重传报文。
我们以 TCP 的四次挥手中第一次挥手为例,当客户端(主动关闭方)调用 close 函数后,就会向服务端发送 FIN 报文,试图与服务端断开连接,此时客户端的连接进入到 FIN_WAIT_1
状态。
正常情况下,如果能及时收到服务端(被动关闭方)的 ACK ,则会很快变为 FIN_WAIT_2
状态。
如果第一次挥手丢失了,那么客户端迟迟收不到被动方的 ACK 的话,也会触发超时重传机制,重传 FIN 报文,重发次数由 tcp_orphan_retries
参数控制。
当客户端重传 FIN 报文的次数超过 tcp_orphan_retries
后,就不再发送 FIN 报文,则会在等待一段时间(时间为上一次超时时间的 2 倍),如果还没能收到第二次挥手,那么直接进入到 close 状态。
定时器的工作原理
定时器是超时重传机制的核心,定时器的作用是等待接收方的确认,如果超时没有收到确认,就进行重传。
- 初始定时器设置:当发送方发送一个数据包时,它会设置一个定时器,并假设接收方在规定时间内收到并确认数据。这个规定时间通常是根据网络环境和 RTT(Round Trip Time,往返时间)来设定的。
- 往返时间 RTT:每次发送数据包时,TCP会估计网络的 RTT ,并根据 RTT 来动态调整定时器的超时时间。这个值越小,重传的等待时间越短,反之越长。
- 动态调整超时:TCP 使用 RTT的估算值 来设置定时器。当连接进行数据传输时,它会记录每次的往返时间 RTT ,并动态调整定时器的超时值。这个值叫做 RTO(Retransmission Timeout),即重传超时时间。RTO 会根据网络的实际延迟自动调节,以避免因过短或过长的超时时间导致过多不必要的重传或超时。
参考:https://xiaolincoding.com/network/3_tcp/tcp_interview.html#%E7%AC%AC%E4%B8%80%E6%AC%A1%E6%8C%A5%E6%89%8B%E4%B8%A2%E5%A4%B1%E4%BA%86-%E4%BC%9A%E5%8F%91%E7%94%9F%E4%BB%80%E4%B9%88