📹 第九章 SIP及eXosip开源库应用
📄 一句话概括

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 秒实验

  1. 把 S.T2 改成 8 秒,重算一次,看次数变成多少。
  2. 把 S.T1 改成 0.1 秒,看重传会密集到什么程度。
  3. 在不封顶的情况下手算序列,找出第一次超过 32 秒的位置。

常见误区

  1. 以为重传是等间隔的。 它是 T1 起翻倍、T2 封顶,所以头几次密、后面疏。 这么做是为了同时对付抖动和丢包。
  2. 以为收到 100 Trying 就万事大吉。 它只停 Timer A,Timer B 还在跑, 收不到最终应答仍要等满 32 秒。
  3. 直接按标准值上线、或者直接把标准值改小。 要看网络类型:局域网 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,把这些变成能编的代码。

相关笔记