在传统电话网里,主叫挂机或者中继信令(ISUP REL)一旦发出,呼叫就结束了。但 SIP(RFC 3261)有一个先天的设计缺口:会话建立之后,SIP 本身并不维护会话的存活状态。一个已确认的 dialog(由 Call-ID、From-tag、To-tag 标识)如果没有任何后续报文交互,它就静静地躺在所有中间网元的会话表里——既不会自我声明"我还活着",也不会主动消亡。
这在 IMS/VoLTE/VoNR 场景下是致命的。设想一个典型故障:用户在通话进行中手机突然掉电、或者驶入无覆盖的隧道、或者 UE 协议栈崩溃,此时 UE 根本来不及发送 BYE。如果没有补救机制,会发生三件糟糕的事情:
为了让 SIP 能"自己发现会话已经死了",IETF 在 RFC 4028(及其 bis 草案 draft-ietf-sipcore-rfc4028bis)中定义了 Session Timer(会话定时器)扩展,3GPP 则在 TS 24.229《IP 多媒体呼叫控制协议(基于 SIP/SDP),Stage 3》中将其纳入 IMS 协议栈作为 UE 与 CSCF 的强制能力,并在 TS 23.228、TS 23.380、TS 32.260 等规范中与 IMS 过程、Rx 接口授权、IMS 计费联动。
本文聚焦 TS 24.229 第 5.1.2 节(UE 发起/终结会话过程)与第 4.5 节(头域支持)中对 Session Timer 的具体过程要求,结合 RFC 4028 的协商/刷新/超时三大机制,做一次全链拆解。
Session Timer 在协议面上一共引入了"两个新头域 + 一个 option-tag + 一个新响应码",外加 refresher 参数。这些 IE 的精确语义是后续所有信令流程的基础。
| 头域 / 参数 | 方向 | 作用 | 典型取值 |
|---|---|---|---|
Session-Expires(缩写 x) |
INVITE / 2xx / 422 | 协商出的会话最大存活时长(delta-seconds) | 1800(30 min,VoLTE 常见) |
refresher= 参数 |
2xx 中确定 | 指定由谁发起周期性刷新 | uac 或 uas |
Min-SE |
INVITE / 422 | 声明能接受的最小刷新间隔,防止刷新过频 | 90(RFC 4028 默认下限 90s) |
Supported: timer |
任意请求/响应 | 声明"我支持但非强制"会话定时器 | option-token timer |
Require: timer |
INVITE / 2xx | 强制对端必须支持会话定时器,否则 420 Bad Extension | timer |
422 Session Interval Too Small |
UAS→UAC | 拒绝过短间隔,并回送本端 Min-SE |
携带 Min-SE: <server min> |
下表把会话定时器与 IMS 中另外两类容易混淆的"保活/刷新"机制放在一起,帮助厘清边界:
| 机制 | 规范来源 | 作用对象 | 触发动作 | 失败后果 |
|---|---|---|---|---|
| Session Timer | RFC 4028 / TS 24.229 | 单个媒体会话(dialog) | re-INVITE / UPDATE 刷新 |
会话级 BYE,释放专用承载与计费 |
| Registration | TS 24.229 / RFC 3261 | 用户注册绑定 | REGISTER(周期重注册) |
注销,所有会话失效 |
| OPTIONS Keepalive | RFC 3262(仅靠它不严谨)/ 厂商实现 | 传输层连通性 | OPTIONS 探测 |
仅断链感知,不释放业务状态 |
可以看到,Session Timer 是唯一一个与媒体资源授权(Rx)和计费紧耦合的会话级存活机制,这也是它在 IMS 里不可被 Registration 或心跳替代的根本原因。
Session Timer 的核心是一次 Offer/Answer 风格的协商。规则可以浓缩为一句话:间隔只能被改小、不能被改大;谁是 refresher,最终由 2xx 一锤定音。
完整协商规则(源自 RFC 4028 §5、TS 24.229 §5.1.2):
Supported: timer(或 Require: timer),并可选地携带 Session-Expires: <value>;refresher=uac|uas 和 Min-SE: <min>。Min-SE,则在 2xx 中回送最终的 Session-Expires(可等于或小于 UAC 提议值,不可更大)以及明确的 refresher 角色。Min-SE;UAC 应据此重发 INVITE。Session-Expires(但不能改大),用于实施运营商策略;代理不能担任 refresher。下面是包含协商、刷新、超时三大阶段的完整时序:
sequenceDiagram
autonumber
participant UE as UE (UAC)
participant PCSCF as P-CSCF
participant SCSCF as S-CSCF
participant UAS as 被叫UE (UAS)
Note over UE,UAS: 阶段1:协商
UE->>PCSCF: INVITE<br/>Supported: timer<br/>Session-Expires:1800;refresher=uac<br/>Min-SE:90
Note over PCSCF: 策略校验/可改小间隔
PCSCF->>SCSCF: INVITE (转发)
SCSCF->>UAS: INVITE (转发)
UAS-->>SCSCF: 200 OK<br/>Session-Expires:1800;refresher=uac
SCSCF-->>PCSCF: 200 OK
Note over PCSCF: 校验Rx授权一致
PCSCF-->>UE: 200 OK (Session-Expires:1800;refresher=uac)
UE->>PCSCF: ACK
Note over UE,UAS: 阶段2:约半个间隔(900s)后刷新
UE->>PCSCF: re-INVITE (无SDP变更)<br/>Session-Expires:1800
PCSCF->>UAS: re-INVITE
UAS-->>PCSCF: 200 OK (Session-Expires:1800)
PCSCF-->>UE: 200 OK
UE->>PCSCF: ACK
Note over UE,UAS: 定时器重置,会话续命
Note over UE,UAS: 阶段3:若刷新始终缺失则超时释放
Note over PCSCF: 间隔到期仍未收到刷新
PCSCF->>UE: BYE (Reason: 会话超时)
Note over PCSCF: 触发Rx STR释放专用承载
设计意图:让间隔"只能减小"是为了防止被中间网元恶意拉长导致无法及时检测失效;让 2xx 拥有最终决定权,是因为被叫方(往往是被叫侧 SBC/UE)最清楚自己期望的刷新负担。Min-SE 与 422 的组合,则是为了避免双方陷入"你刷新太快、我也刷新太快"的资源浪费螺旋。
确定 refresher 之后,refresher 一方承担周期性刷新义务。RFC 4028 给出的实践做法是:refresher 在约半个协商间隔处发送一次刷新请求(例如 1800s 的间隔,则在 ~900s 左右刷新),这样即便首次刷新丢失,仍有充足时间重试,避免误判。
刷新报文有两种选择,二者分工明确:
| 刷新方式 | 规范 | 适用阶段 | 是否携带 SDP | IMS 中的典型用途 |
|---|---|---|---|---|
| re-INVITE | RFC 3261 + 4028 | 早期/确认后均可,刷新确认后的 dialog | 可不带 SDP(仅刷新) | 通话中周期续命首选 |
| UPDATE | RFC 3311 | 主要用于早期 dialog(含早期媒体) | 通常带 SDP | 振铃期间刷新/媒体变更 |
在确认后的通话里,re-INVITE(不带 SDP,或带与上次完全相同的 SDP)是最常见的纯刷新手段,因为它只刷新定时器而不触发媒体面任何动作。需要注意两个工程细节:
Session-Expires,对端在 2xx 中再次确认(通常保持不变),定时器以最新一次 2xx 为基准重新计时。下图给出 refresher 与非 refresher 双方的内部状态机,对工程实现和抓包诊断都很有用:
stateDiagram-v2
[*] --> 协商中: 发送/接收 INVITE
协商中 --> 活跃: 收到2xx<br/>确定refresher与间隔
活跃 --> 等待刷新: 我是refresher,计时到半间隔
等待刷新 --> 活跃: 发re-INVITE收到2xx
等待刷新 --> 释放中: 刷新无响应(408/481)
活跃 --> 释放中: 我是非refresher<br/>且间隔已满仍无刷新
释放中 --> [*]: 发送/接收BYE<br/>拆除媒体与授权
协商中 --> [*]: 422重试或拒绝
当 refresher 在整个会话间隔内都没有成功刷新(既可能是 UE 失联,也可能是刷新请求在网络中丢失且重试也失败),Session Timer 机制进入"超时释放"分支。这是该机制真正的价值所在,也是它与 IMS 用户面/计费面联动的关键点。
以主叫 UE 担任 refresher、但 UE 突然掉电为例,P-CSCF 侧会发生如下动作(结合 TS 23.228 与 TS 29.214 Rx 接口过程):
sequenceDiagram
autonumber
participant UE as 主叫UE(refresher,已失联)
participant PCSCF as P-CSCF
participant PCRF as PCF/PCRF
participant SMF as SMF (会话管理)
participant SCSCF as S-CSCF
Note over UE: 掉电/脱网,无法发出re-INVITE
Note over PCSCF: 本地会话定时器到期,<br/>未收到任何刷新
PCSCF->>PCRF: Rx STR (Session-Termination-Request)<br/>移除GBR承载授权
PCRF-->>PCSCF: Rx STA
PCRF->>SMF: 策略:释放5QI=1专用QoS流
SMF->>SMF: 拆除专用承载/通知(R)AN
PCSCF->>SCSCF: BYE (向IMS核心释放会话)
SCSCF-->>PCSCF: 200 OK
Note over PCSCF,SCSCF: AS侧触发CDR停止计费
PCSCF-x UE: BYE (尽力发送,通常丢弃)
要点解析:
BYE 完成 IMS 会话清理。这套设计把"协议层存活检测"和"资源/计费回收"绑定在一起,是 IMS 区别于普通 SIP 网络的关键工程实践。
把上文 IE 与流程中用到的报文结构做一次可视化,便于在抓包时快速对位:
flowchart TB
subgraph INV["初始INVITE相关头域"]
A["Supported: timer"] --> A1["声明支持,非强制"]
A2["Require: timer"] --> A2a["强制对端支持,否则420"]
A3["Session-Expires: 1800"] --> A3a["delta-seconds"]
A3 --> A3b["refresher=uac"]
A4["Min-SE: 90"] --> A4a["可接受最小间隔"]
end
subgraph OK["2xx/刷新响应"]
B["Session-Expires: 1800;refresher=uac"] --> B1["最终协商值,只能<=提议"]
B --> B2["双方均以2xx为准重置定时器"]
end
subgraph ERR["异常响应"]
C["422 Session Interval Too Small"] --> C1["回送Min-SE"]
C --> C2["UAC据此放大间隔重试"]
D["491 Request Pending"] --> D1[" glare退避后重试"]
E["408/481"] --> E1["刷新失败,触发超时释放"]
end
在真实网络(UERANSIM/free5GC、爱立信/华为/中兴 IMS 核心网)抓包时,Session Timer 的指纹非常清晰:
sip.Session-Expires 过滤,初始 INVITE 的 2xx 必带 Session-Expires: N;refresher=...。若该头缺失且网络要求支持,说明 UE 没声明 Supported: timer。Request: INVITE(CSeq 递增)紧跟 Status: 200 OK + ACK,且 SDP 与之前一致(或无 SDP)。这是最典型的续命三轮。BYE,且 P-CSCF 之前有 Rx STR/STA,即可判定为超时释放。常见故障与排错思路:
| 现象 | 可能根因 | 排错方向 |
|---|---|---|
| 初始 INVITE 被 420 Bad Extension 拒绝 | UE 用 Require: timer 但被叫不支持 |
改用 Supported: timer,由被叫决定是否启用 |
| 频繁 422 导致呼叫建立失败 | UAC 提议间隔 < 网元 Min-SE |
检查 P-CSCF/SBC 的 Min-SE 策略,放大 INVITE 间隔 |
| 通话每隔固定时长自动挂断 | 刷新请求(re-INVITE)丢失或被对端忽略 | 抓包确认刷新三轮是否完整;查 NAT/SBC 对 re-INVITE 的处理 |
| 长时间"幽灵会话"未释放 | P-CSCF 未启用 Session Timer 或 Session-Expires 未下发 |
核查 P-CSCF 策略、Rx 授权与会话表联动 |
| 主被叫同时 re-INVITE 卡死 | 491 退避逻辑未实现/实现错误 | 检查 UAS 对 491 的随机重试实现 |
| ## 九、常见问题 |
Q1:Session Timer 和 SIP Registration 重注册有什么区别? A:Registration 维护的是"用户是否在网络里注册"的绑定关系,周期通常很长(数十分钟到数小时),失败导致整个用户注销、所有会话失效;Session Timer 维护的是"单个媒体会话是否存活",周期短(分钟级),只影响该会话本身。一个用户注册有效但某个通话的 Session Timer 超时,是完全正常的情况。
Q2:为什么 refresher 默认建议在"半个间隔"处刷新,而不是临近到期? A:留出另一半时间作为容错窗口。若临近到期才刷新,一旦该刷新请求丢包,重试尚未成功定时器就到点,会误判释放健康会话。半间隔刷新保证即便首次失败也有充足时间重传。
Q3:422 和 420 都会让 INVITE 失败,二者区别?
A:420 Bad Extension 是"对端根本不支持这个 option-tag(timer)";422 Session Interval Too Small 是"对端支持 timer,但嫌你提议的间隔太短",并在响应里给出可接受的最小值 Min-SE,引导 UAC 放大间隔后重试。前者要改用法(Supported 而非 Require),后者要改数值。
Q4:刷新时用 re-INVITE 还是 UPDATE,标准上怎么界定? A:确认后的 dialog 用 re-INVITE 刷新是惯例;UPDATE(RFC 3311)更常用于早期 dialog(含早期媒体)的刷新与媒体协商。RFC 4028 允许两者都用于刷新,但实践中 re-INVITE 不带 SDP 是"纯刷新"的最低开销方式。
Q5:在 5G/VoNR 里,Session Timer 触发的承载释放走哪条路? A:仍是 P-CSCF →(Rx)→ PCF → SMF 的路径。PCF 通过 Npcf_SmPolicyControl 通知 SMF,SMF 发起 N4 会话修改,拆除 5QI=1 的专用 QoS Flow,并通知 (R)AN 释放对应 DRB;SIP 层同时发 BYE。这与 4G 经 PCRF→PGW→SGW 链路在概念上一一对应,只是网元名与接口换成了 5G SBA 体系。
本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
