面试题答案
一键面试TCP重传机制的实现
- 重传定时器:在TCP协议栈中,每个TCP连接都维护一个重传定时器(Retransmission Timer, RTO)。当TCP发送一个报文段后,会启动这个定时器。如果在定时器超时之前没有收到对应的确认(ACK),则认为该报文段丢失,需要重传。
- 例如在Linux内核源码(以较新的版本为例,如5.x内核)中,
tcp_output.c
文件中的tcp_transmit_skb
函数,在发送报文段时会调用tcp_reset_xmit_timer
函数启动重传定时器。
int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, gfp_t gfp_mask) { // 发送报文段相关操作 tcp_reset_xmit_timer(sk, TCP_WRITE_TIMER, tcp_time_stamp + tcp_rto(sk), TCP_RTO_MAX); return 1; }
- 例如在Linux内核源码(以较新的版本为例,如5.x内核)中,
- 重传队列:TCP会将已发送但未确认的报文段放入重传队列(retransmission queue)。当需要重传时,从这个队列中取出报文段进行重传。
- 在Linux内核中,
tcp_out.c
文件里有相关数据结构和操作来管理重传队列。struct tcp_sock
结构体中有成员用于记录重传队列相关信息,例如retrans_out
记录重传队列中的字节数等。
struct tcp_sock { // 其他成员 unsigned int retrans_out; // 更多与重传队列相关的成员 };
- 在Linux内核中,
- 重传策略:
- 快速重传:当TCP接收到多个重复的ACK时(通常是3个重复ACK),认为可能发生了报文段丢失,但网络状况可能还不错,此时会触发快速重传机制,不等重传定时器超时就重传丢失的报文段。在Linux内核中,
tcp_input.c
文件的tcp_fastretrans_alert
函数处理快速重传相关逻辑。
void tcp_fastretrans_alert(struct sock *sk, struct sk_buff *skb, int flag) { // 处理快速重传逻辑,如重传报文段等操作 }
- 超时重传:如果重传定时器超时,TCP会从重传队列中重传最早未确认的报文段,并重新启动重传定时器,且一般会加倍重传超时时间(指数退避)。在
tcp_timer.c
文件的tcp_write_timer
函数中处理超时重传逻辑。
void tcp_write_timer(struct sock *sk) { // 检查重传队列,重传最早未确认的报文段 tcp_reset_xmit_timer(sk, TCP_WRITE_TIMER, tcp_time_stamp + tcp_rto(sk), TCP_RTO_MAX); }
- 快速重传:当TCP接收到多个重复的ACK时(通常是3个重复ACK),认为可能发生了报文段丢失,但网络状况可能还不错,此时会触发快速重传机制,不等重传定时器超时就重传丢失的报文段。在Linux内核中,
重传超时时间(RTO)的计算和调整
- 初始RTO的计算:在TCP连接建立时,会初始化RTO。通常初始RTO有一个默认值,例如在Linux内核中,默认初始RTO为3秒(
TCP_RTO_MIN
,在include/net/tcp.h
中定义)。#define TCP_RTO_MIN ((unsigned)(HZ/3)) /* 300ms */
- 基于往返时间(RTT)的计算:TCP会不断测量报文段的往返时间(Round - Trip Time, RTT)。每次收到ACK时,会根据新测量的RTT来调整RTO。
- 平滑往返时间(Smoothed RTT, SRTT)的计算:
SRTT = (1 - α) * SRTT + α * RTT
,其中α是一个平滑因子,通常取值为1/8。 - 偏差(Deviation, RTTD)的计算:
RTTD = (1 - β) * RTTD + β * |RTT - SRTT|
,β通常取值为1/4。 - RTO的计算:
RTO = SRTT + 4 * RTTD
。 - 在Linux内核中,
tcp_input.c
文件的tcp_time_stamp
函数在收到ACK时更新RTT相关统计信息,进而影响RTO的计算。
void tcp_time_stamp(struct sock *sk, struct sk_buff *skb, int flag) { // 计算和更新RTT、SRTT、RTTD等相关值,影响RTO计算 }
- 平滑往返时间(Smoothed RTT, SRTT)的计算:
- RTO的调整:
- 指数退避:当发生超时重传时,RTO会加倍(指数退避),以避免在网络拥塞时频繁重传加重网络负担。例如在
tcp_timer.c
文件的tcp_write_timer
函数中,当超时重传发生时,会调用tcp_ca_event
函数,在拥塞控制算法中会对RTO进行加倍等调整。
void tcp_write_timer(struct sock *sk) { // 重传操作 tcp_ca_event(sk, TCP_EVENT_RETRANS_TIMEOUT); }
- 快速恢复:在快速重传后进入快速恢复阶段,RTO可能会根据具体的拥塞控制算法(如TCP Reno、TCP NewReno等)进行调整,一般不会进行指数退避那样大幅度的增长,而是相对温和地调整以适应网络状况。
- 指数退避:当发生超时重传时,RTO会加倍(指数退避),以避免在网络拥塞时频繁重传加重网络负担。例如在