第17章 TCP:定时器

所属:TCP/IP详解 卷2:实现 来源:TCP/IP详解 卷2:实现

本章描述TCP的各种定时器,包括重传定时器、坚持定时器、保活定时器和2MSL定时器的实现。


17.1 引言

TCP定时器的作用

TCP定时器的作用:

  • 处理超时和重传
  • 处理零窗口
  • 处理空闲连接
  • 处理TIME_WAIT状态
  • 保证协议的正确性和健壮性

定时器是TCP可靠性的重要保障。


TCP的四个定时器

TCP有四个主要的定时器:

定时器作用
重传定时器(retransmission)超时重传数据
坚持定时器(persist)窗口探查,防止零窗口死锁
保活定时器(keepalive)探查空闲连接是否还活着
2MSL定时器TIME_WAIT状态等待

四个定时器各有各的作用。


本章讨论的内容

本章讨论的内容:

  • 定时器的管理
  • 重传定时器
  • RTT测量和RTO计算
  • 坚持定时器
  • 保活定时器
  • 2MSL定时器

本章详细讨论TCP的各种定时器。


17.2 定时器的管理

定时器的实现方式

TCP定时器的实现:

  • 每个连接有多个定时器
  • 用计数器表示剩余时间
  • 每500ms(慢速超时)减1
  • 减到0就触发超时

为什么用500ms:

  • 内核的慢速超时是500ms一次
  • 方便管理
  • 精度足够

定时器用计数器,每500ms减1。


定时器数组

每个tcpcb有一个定时器数组:

int t_timer[TCPT_NTIMERS];   /* 定时器数组 */

定时器索引:

索引名称说明
TCPT_REXMT重传定时器重传超时
TCPT_PERSIST坚持定时器窗口探查
TCPT_KEEP保活定时器保活探查
TCPT_2MSL2MSL定时器TIME_WAIT等待

四个定时器用数组管理。


定时器的启动和停止

启动定时器:

  • 设置对应的计数器值
  • 单位是500ms(ticks)
  • 例如:RTO=3秒 → 计数器=6

停止定时器:

  • 把计数器设为0
  • 0表示定时器没运行

检查定时器:

  • 每500ms检查一次
  • 计数器>0就减1
  • 减到0就触发超时处理

启动、停止、检查是基本操作。


tcp_slowtimo函数

tcp_slowtimo函数:

  • 慢速超时处理函数
  • 每500ms调用一次
  • 遍历所有TCP连接
  • 每个定时器减1
  • 减到0就处理超时
void
tcp_slowtimo()
{
    /*
     * 遍历所有TCP连接
     * 每个定时器减1
     * 超时则处理
     */
}

tcp_slowtimo是定时器的核心。


17.3 重传定时器

重传定时器的作用

重传定时器的作用:

  • 发送数据后启动
  • 超时没收到ACK就重传
  • 保证数据可靠交付
  • TCP可靠性的核心

重传定时器保证数据可靠。


什么时候启动

启动重传定时器的时机:

  • 发送数据时
  • 发送SYN/FIN时
  • 发送后如果还有未确认的数据

停止重传定时器的时机:

  • 所有数据都被确认了
  • 连接关闭

有未确认数据就启动,都确认了就停止。


重传超时的处理

重传超时的处理:

  1. 重传最早的未确认段
  2. 拥塞窗口减小
  3. 慢启动阈值调整
  4. RTO翻倍(指数退避)
  5. 重新启动定时器

指数退避:

  • 第一次超时:RTO
  • 第二次:2×RTO
  • 第三次:4×RTO
  • 以此类推
  • 直到上限

超时后指数退避,避免网络更拥塞。


17.4 RTT测量和RTO计算

为什么要测量RTT

RTT(Round-Trip Time):

  • 往返时间
  • 从发送到收到ACK的时间
  • 用于计算RTO(Retransmission TimeOut)

为什么要测量:

  • RTO不能是固定的
  • 不同网络RTT不同
  • 同一网络RTT也会变化
  • RTO要适应RTT的变化

RTO要根据RTT动态调整。


RTO的计算

RTO的计算公式(经典算法):

SRTT = α × SRTT + (1-α) × RTT
RTTVAR = β × RTTVAR + (1-β) × |RTT - SRTT|
RTO = SRTT + 4 × RTTVAR
  • SRTT:平滑RTT(Smoothed RTT)
  • RTTVAR:RTT方差(RTT Variance)
  • α:平滑因子,通常1/8
  • β:方差因子,通常1/4

RTO由SRTT和RTTVAR计算。


Karn算法

Karn算法:

  • 重传的段不用于RTT测量
  • 因为不知道是第一次的ACK还是重传的ACK
  • 避免歧义

为什么需要:

  • 重传后收到ACK
  • 不知道是对哪个的ACK
  • 测量会不准
  • 所以重传的不测量

Karn算法解决重传的RTT测量歧义。


RTT测量的实现

RTT测量的实现:

  • 记录发送的序号和时间
  • 收到ACK时,如果匹配就计算RTT
  • 更新SRTT和RTTVAR
  • 重传的不测量(Karn算法)

相关字段:

  • t_rtt:当前RTT测量值(如果在测量)
  • t_rttseq:测量的起始序号
  • t_srtt:平滑RTT
  • t_rttvar:RTT方差

记录序号,收到ACK时计算。


17.5 坚持定时器

坚持定时器的作用

坚持定时器(persist timer)的作用:

  • 防止零窗口死锁
  • 对端通告窗口为0
  • 之后窗口恢复了,但ACK丢了
  • 两边都等对方,死锁
  • 坚持定时器周期性探查

坚持定时器防止零窗口死锁。


什么时候启动

启动坚持定时器的时机:

  • 发送时发现窗口为0
  • 不能发送数据
  • 启动坚持定时器

停止坚持定时器的时机:

  • 收到非零窗口的ACK
  • 可以发送数据了

窗口为0就启动,窗口恢复就停止。


坚持定时器的处理

坚持定时器超时的处理:

  1. 发送窗口探查(1字节的数据)
  2. 对端收到后回复ACK
  3. ACK中包含新的窗口大小
  4. 如果窗口还是0,重新启动坚持定时器
  5. 超时时间指数退避

探查的特点:

  • 只发1字节
  • 即使窗口为0也能发
  • 用来试探窗口

周期性探查窗口是否恢复。


17.6 保活定时器

保活定时器的作用

保活定时器(keepalive timer)的作用:

  • 探查空闲连接是否还活着
  • 长时间没有数据
  • 不确定对端是否还在
  • 定期发送探查

为什么需要:

  • 对端崩溃了,没发FIN
  • 连接一直挂着
  • 浪费资源
  • 保活可以发现这种情况

保活定时器探查空闲连接。


保活的争议

保活的争议:

反对的理由:

  • 可能误判(临时网络问题)
  • 浪费带宽
  • 不是TCP标准要求的
  • 应用层应该自己处理

支持的理由:

  • 可以及时发现死连接
  • 释放资源
  • 很多应用需要

结论:

  • 可选功能
  • 默认关闭
  • 需要时开启

保活是可选的,有争议。


保活的实现

保活的实现:

  • 连接空闲一段时间后启动
  • 定期发送探查段
  • 收到应答就重置定时器
  • 几次没应答就认为连接断了

时间线(典型值):

  1. 空闲2小时后开始探查
  2. 每隔75秒发一个探查
  3. 发10个都没应答
  4. 认为连接断开

空闲很久才开始探查,频率很低。


17.7 2MSL定时器

2MSL定时器的作用

2MSL定时器的作用:

  • TIME_WAIT状态
  • 等待2MSL(Maximum Segment Lifetime)
  • 确保最后一个ACK到达对端
  • 确保旧的连接的分组都消失了

MSL:

  • 最大分节生命期
  • 分组在网络中最长存活时间
  • RFC建议2分钟
  • 实际常用30秒到2分钟

2MSL等待确保连接可靠关闭。


为什么需要TIME_WAIT

为什么需要TIME_WAIT:

  1. 确保最后一个ACK到达

    • 主动关闭的最后发ACK
    • ACK可能丢
    • 对端会重发FIN
    • TIME_WAIT时还能重发ACK
    • 不然对端会一直重传
  2. 确保旧的分组消失

    • 防止旧连接的分组
    • 被新连接当成新的
    • 等2MSL,旧的都没了

两个原因:可靠关闭和防止混淆。


2MSL定时器的实现

2MSL定时器的实现:

  • 进入TIME_WAIT状态时启动
  • 设置为2MSL(单位ticks)
  • 超时后关闭连接
  • 释放资源

2MSL的典型值:

  • MSL=30秒 → 2MSL=60秒
  • MSL=1分钟 → 2MSL=2分钟
  • 不同实现可能不同

等待2MSL后彻底关闭。


17.8 小结

定时器管理

  1. 实现方式

    • 计数器
    • 每500ms减1
    • 减到0触发超时
  2. 定时器数组

    • 重传、坚持、保活、2MSL
    • 数组管理
  3. tcp_slowtimo

    • 每500ms调用
    • 遍历所有连接
    • 处理超时

重传定时器

  1. 作用

    • 超时重传
    • 保证可靠
  2. 启动停止

    • 有未确认数据就启动
    • 都确认了就停止
  3. 超时处理

    • 重传数据
    • 拥塞窗口调整
    • 指数退避

RTT和RTO

  1. RTT测量

    • 测量往返时间
    • 用于计算RTO
  2. RTO计算

    • SRTT + 4×RTTVAR
    • 平滑估计
  3. Karn算法

    • 重传的不测量
    • 避免歧义

坚持定时器

  1. 作用

    • 防止零窗口死锁
    • 窗口探查
  2. 启动停止

    • 窗口为0启动
    • 窗口恢复停止
  3. 超时处理

    • 发1字节探查
    • 指数退避

保活定时器

  1. 作用

    • 探查空闲连接
    • 发现死连接
  2. 争议

    • 可选功能
    • 有争议
  3. 实现

    • 空闲很久才开始
    • 定期探查
    • 几次没应答就断开

2MSL定时器

  1. 作用

    • TIME_WAIT状态
    • 等待2MSL
  2. 为什么需要

    • 确保最后ACK到达
    • 确保旧分组消失
  3. 实现

    • 进入TIME_WAIT启动
    • 超时关闭连接

关键概念

  1. 四个定时器

    • 重传、坚持、保活、2MSL
    • 各有各的作用
  2. 定时器管理

    • 计数器
    • 500ms一次
    • tcp_slowtimo
  3. RTT和RTO

    • 测量RTT
    • 计算RTO
    • Karn算法
  4. TIME_WAIT

    • 2MSL等待
    • 两个原因

定时器