第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_2MSL | 2MSL定时器 | 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时
- 发送后如果还有未确认的数据
停止重传定时器的时机:
- 所有数据都被确认了
- 连接关闭
有未确认数据就启动,都确认了就停止。
重传超时的处理
重传超时的处理:
- 重传最早的未确认段
- 拥塞窗口减小
- 慢启动阈值调整
- RTO翻倍(指数退避)
- 重新启动定时器
指数退避:
- 第一次超时: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字节的数据)
- 对端收到后回复ACK
- ACK中包含新的窗口大小
- 如果窗口还是0,重新启动坚持定时器
- 超时时间指数退避
探查的特点:
- 只发1字节
- 即使窗口为0也能发
- 用来试探窗口
周期性探查窗口是否恢复。
17.6 保活定时器
保活定时器的作用
保活定时器(keepalive timer)的作用:
- 探查空闲连接是否还活着
- 长时间没有数据
- 不确定对端是否还在
- 定期发送探查
为什么需要:
- 对端崩溃了,没发FIN
- 连接一直挂着
- 浪费资源
- 保活可以发现这种情况
保活定时器探查空闲连接。
保活的争议
保活的争议:
反对的理由:
- 可能误判(临时网络问题)
- 浪费带宽
- 不是TCP标准要求的
- 应用层应该自己处理
支持的理由:
- 可以及时发现死连接
- 释放资源
- 很多应用需要
结论:
- 可选功能
- 默认关闭
- 需要时开启
保活是可选的,有争议。
保活的实现
保活的实现:
- 连接空闲一段时间后启动
- 定期发送探查段
- 收到应答就重置定时器
- 几次没应答就认为连接断了
时间线(典型值):
- 空闲2小时后开始探查
- 每隔75秒发一个探查
- 发10个都没应答
- 认为连接断开
空闲很久才开始探查,频率很低。
17.7 2MSL定时器
2MSL定时器的作用
2MSL定时器的作用:
- TIME_WAIT状态
- 等待2MSL(Maximum Segment Lifetime)
- 确保最后一个ACK到达对端
- 确保旧的连接的分组都消失了
MSL:
- 最大分节生命期
- 分组在网络中最长存活时间
- RFC建议2分钟
- 实际常用30秒到2分钟
2MSL等待确保连接可靠关闭。
为什么需要TIME_WAIT
为什么需要TIME_WAIT:
-
确保最后一个ACK到达
- 主动关闭的最后发ACK
- ACK可能丢
- 对端会重发FIN
- TIME_WAIT时还能重发ACK
- 不然对端会一直重传
-
确保旧的分组消失
- 防止旧连接的分组
- 被新连接当成新的
- 等2MSL,旧的都没了
两个原因:可靠关闭和防止混淆。
2MSL定时器的实现
2MSL定时器的实现:
- 进入TIME_WAIT状态时启动
- 设置为2MSL(单位ticks)
- 超时后关闭连接
- 释放资源
2MSL的典型值:
- MSL=30秒 → 2MSL=60秒
- MSL=1分钟 → 2MSL=2分钟
- 不同实现可能不同
等待2MSL后彻底关闭。
17.8 小结
定时器管理
-
实现方式
- 计数器
- 每500ms减1
- 减到0触发超时
-
定时器数组
- 重传、坚持、保活、2MSL
- 数组管理
-
tcp_slowtimo
- 每500ms调用
- 遍历所有连接
- 处理超时
重传定时器
-
作用
- 超时重传
- 保证可靠
-
启动停止
- 有未确认数据就启动
- 都确认了就停止
-
超时处理
- 重传数据
- 拥塞窗口调整
- 指数退避
RTT和RTO
-
RTT测量
- 测量往返时间
- 用于计算RTO
-
RTO计算
- SRTT + 4×RTTVAR
- 平滑估计
-
Karn算法
- 重传的不测量
- 避免歧义
坚持定时器
-
作用
- 防止零窗口死锁
- 窗口探查
-
启动停止
- 窗口为0启动
- 窗口恢复停止
-
超时处理
- 发1字节探查
- 指数退避
保活定时器
-
作用
- 探查空闲连接
- 发现死连接
-
争议
- 可选功能
- 有争议
-
实现
- 空闲很久才开始
- 定期探查
- 几次没应答就断开
2MSL定时器
-
作用
- TIME_WAIT状态
- 等待2MSL
-
为什么需要
- 确保最后ACK到达
- 确保旧分组消失
-
实现
- 进入TIME_WAIT启动
- 超时关闭连接
关键概念
-
四个定时器
- 重传、坚持、保活、2MSL
- 各有各的作用
-
定时器管理
- 计数器
- 500ms一次
- tcp_slowtimo
-
RTT和RTO
- 测量RTT
- 计算RTO
- Karn算法
-
TIME_WAIT
- 2MSL等待
- 两个原因