SIP 的超时全靠十个命名计时器,其中只有四个会在实际调试中碰到。 重传不是等间隔的:0.5、1.5、3.5、7.5 秒,很快到 4 秒封顶。
09.01.02 讲事务层时提过「重传由它管」,这一节把那些计时器列清。 01.04.04 讲 RTSP 的 Session 超时是「60 秒没动静就回收」, SIP 的超时是另一套:它按「消息类型」分了很多个。
一、十个计时器
| Timer | 时长 | 管什么 |
|---|---|---|
| A | T1 起翻倍 | INVITE 请求重传 |
| B | 64×T1 = 32 秒 | 等 INVITE 应答 |
| D | ≥32 秒 | UDP 下 ACK 之后等 |
| E | T1 起翻倍、上限 T2 | 非 INVITE 请求重传 |
| F | 64×T1 | 等非 INVITE 应答 |
| G | T1 起翻倍、上限 T2 | 2xx 应答重传 |
| H | 64×T1 | 等 ACK |
| I | T4 = 5 秒 | ACK 之后收尾 |
| J | 64×T1 | 非 INVITE 服务端收尾 |
| K | T4 = 5 秒 | 非 INVITE 客户端收尾 |
加粗的那四个(A、B、G、H)是 INVITE 专用的, 也是实际调试中唯一会碰到的——其余六个在正常通话里根本不会触发。 为什么 INVITE 要多两个? 因为它是唯一「需要三次确认」的请求:请求要重传(A),应答要重传(G),ACK 要等(H)。 别的方法只要「请求重传 + 应答超时」两个就够。
二、T1、T2、T4 三个基数
十个计时器全是从三个数推出来的:
| 基数 | 默认值 | 作用 |
|---|---|---|
| T1 | 500 毫秒 | 重传的起始间隔 |
| T2 | 4 秒 | 重传间隔的上限 |
| T4 | 5 秒 | 网络最大滞留时间 |
第二行那个 T2 的作用是「封顶」:重传间隔从 T1 翻倍涨,涨到 T2 就不再涨了。 没有这个上限,间隔会指数爆炸——第 20 次重传就是几百秒后了,等于放弃。 第三行那个 T4 是「一个包在网络里最多活多久」的估计, 它决定了「等多久才能认为对方确实没收到」。 这三个数在 RFC 里是「可配置但有默认」, 所以不同实现的 SIP 栈里数字可能不同——排障时别假设对端用的是 500 毫秒。
三、重传节奏算一遍
从 T1 起翻倍、到 T2 封顶、累计到 32 秒:
| 第几次 | 时间点 | 间隔 |
|---|---|---|
| 1 | 0.5 秒 | 0.5 |
| 2 | 1.5 秒 | 1.0 |
| 3 | 3.5 秒 | 2.0 |
| 4 | 7.5 秒 | 4.0 |
| 5 | 11.5 秒 | 4.0 |
| 10 | 31.5 秒 | 4.0 |
前四次是翻倍期,第五次开始封顶—— 一共 10 次重传,最后一次落在 31.5 秒,然后 Timer B 判超时。 这个设计的意思很清楚:网络抖动是毫秒级的,所以头几次要密; 真丢包是秒级的,所以后面要疏。 注意第四行之后间隔恒为 4 秒:这就是 T2 在起作用,如果没有它,第 10 次会是 256 秒。
四、Timer B 的 32 秒很难受
这是现场调试最常抱怨的一条:
| 情况 | 会发生什么 |
|---|---|
| 收到 100 后不再回 | 干等 32 秒 |
| 完全没回应 | 重传 10 次后超时 |
| 设备重启中 | 同样 32 秒 |
第一行那种情况最坑:100 Trying 停了 Timer A(不再重传),但 Timer B 还在跑。 所以「收到 100 之后没下文」要等满 32 秒才报错。 32 秒在调试时非常难受,很多客户端把 Timer B 改小(比如 8 秒), 代价是弱网下会误判超时。 这就是「标准值」和「工程值」的差别:RFC 给的是能兼容全网的最大值,不是每个场景的最优值。 改它之前要想清楚:你面对的是局域网还是公网——局域网的 8 秒绰绰有余,公网可能要 30 秒。
五、改超时之前先想三件事
| 要问自己 | 为什么 |
|---|---|
| 对端会不会重传 | 改小了会误判 |
| 并发量多大 | 超时期间占着资源 |
| 用户能等多久 | 32 秒没人受得了 |
第一行是技术底线:如果对端按 RFC 节奏重传,你的超时比它的重传间隔短,就一定误判。 第三行是产品底线:「点播转了半分钟才报错」在监控客户端上不可接受, 所以真实产品普遍会把「界面超时」和「协议超时」分开—— 界面 3 秒就提示「正在重试」,协议层仍然等 32 秒。 这个「两层超时」的做法值得学:它既没违反规范,又没让用户干等。
六、动手 Demo:十个 Timer,只有四个真常用
Demo 把十个计时器列成表,再用代码算一遍重传时间点。 表里的时长都是从 T1、T2、T4 推出来的,不是查表抄的。
ts = S.backoff() # T1=0.5, T2=4, 上限 64*T1
for i, t in enumerate(ts, 1):
prev = ts[i - 2] if i > 1 else 0
print(i, "%.2f" % t, "%.2f" % (t - prev))
print(len(ts), ts[-1])
实跑输出:
--------------------------------------------------------------------
十个 Timer,只有四个真常用
--------------------------------------------------------------------
**SIP 的超时全靠命名计时器,RFC 3261 里一共十个。**
**(还有一个 Timer C 已经废弃,不算在这里。)**
Timer 时长 管什么
----------------------------------------------------------
A T1(0.5 秒)起翻倍 **INVITE 请求重传**
B 64×T1 = 32 秒 **等 INVITE 应答总时长**
D ≥32 秒 UDP 下 ACK 之后等
E T1 起翻倍、上限 T2 非 INVITE 请求重传
F 64×T1 = 32 秒 等非 INVITE 应答
G T1 起翻倍、上限 T2 **2xx 应答重传**
H 64×T1 = 32 秒 等 ACK
I T4 = 5 秒 ACK 之后收尾
J 64×T1 非 INVITE 服务端收尾
K T4 = 5 秒 非 INVITE 客户端收尾
**最后一列加粗的那四个(A、B、G、H)是 INVITE 专用的**,
**也是实际调试中唯一会碰到的**——**其余六个在正常通话里根本不会触发。**
**T1 起翻倍到底是什么节奏,算一遍**:
第几次 时间点(秒) 间隔(秒)
---------------------------------------
1 0.50 0.50
2 1.50 1.00
3 3.50 2.00
4 7.50 4.00
5 11.50 4.00
6 15.50 4.00
7 19.50 4.00
8 23.50 4.00
9 27.50 4.00
10 31.50 4.00
**一共 10 次重传,最后一次落在 31.50 秒**,**然后 Timer B 到 32 秒判超时。**
**注意第二列不是等差的**:**0.5、1.5、3.5、7.5……每次间隔翻倍,很快到 4 秒封顶。**
**这个设计的意思很清楚**:**网络抖动是毫秒级的,所以头几次要密**;
**真丢包是秒级的,所以后面要疏。**
**现场最容易踩的一条**:**100 Trying 一到就停 Timer A**,**但 Timer B 不停**——
**所以「收到 100 之后再也不回 200」这种情况**,客户端会干等 32 秒才报超时。
**32 秒在调试时非常难受**,**很多客户端把 Timer B 改小(比如 8 秒)**,**代价是弱网下会误判。**
**这就是「标准值」和「工程值」的差别**:**RFC 给的是能兼容全网的最大值,不是每个场景的最优值。**
输出里那十行就是完整的重传计划:最后一列从 0.5 涨到 4 就停住了,这是 T2 封顶在起作用。 一共 10 次、末次 31.5 秒——这个数正好卡在 Timer B 的 32 秒之前, 说明规范是「算好了」的:重传不会超过总超时。 如果 T2 不封顶会怎样? 间隔是 0.5、1、2、4、8、16、32…… 第 7 次就到 63.5 秒了,远超 32 秒的总限—— 所以 T2 不只是「省流量」,它是「保证重传都在超时之内」的必要条件。 表里那个 Timer D 写的是「≥32 秒」而不是具体值,因为规范只给了下限,实现可以更长—— 这也是为什么不同设备的「挂断后还能收到 ACK」时间不一样。
30 秒实验
- 把
S.T2改成 8 秒,重算一次,看次数变成多少。 - 把
S.T1改成 0.1 秒,看重传会密集到什么程度。 - 在不封顶的情况下手算序列,找出第一次超过 32 秒的位置。
常见误区
- 以为重传是等间隔的。 它是 T1 起翻倍、T2 封顶,所以头几次密、后面疏。 这么做是为了同时对付抖动和丢包。
- 以为收到 100 Trying 就万事大吉。 它只停 Timer A,Timer B 还在跑, 收不到最终应答仍要等满 32 秒。
- 直接按标准值上线、或者直接把标准值改小。 要看网络类型:局域网 8 秒够、 公网可能要 30 秒;改小了会误判。
自测三问(点开对答案)
1. 十个计时器是怎么推出来的? —— **全从 T1(500 毫秒)、T2(4 秒)、T4(5 秒)三个基数推**。 重传用 T1 翻倍到 T2 封顶,超时用 64×T1。 2. 为什么 INVITE 比其他方法多两个计时器? —— **它是唯一需要三次确认的请求**:请求重传(A)、应答重传(G)、等 ACK(H)。 其他方法只有请求重传与应答超时。 3. T2 封顶的真正作用是什么? —— **保证所有重传都落在 32 秒总限之内**。 不封顶的话第 7 次就超过总超时了,重传计划本身就不成立。09.01 到此结束: SIP 的报文、标识、流程、超时全走了一遍。下一节进 eXosip,把这些变成能编的代码。
- ☐ (本节完,下一节 09.02.01 oSIP及eXosip简介)