在 IMS/VoNR 体系中,一条语音呼叫的本质是一个 SIP dialog(会话),它由 Call-ID、From-tag、To-tag 三元组唯一标识,并沿路在 UE、P-CSCF、S-CSCF、SBC/IBCF、对端 UE 之间维护着大量的状态机与媒体资源(IPSec SA、RTP 端口、QoS 承载、计费会话)。
问题在于:SIP 是基于事务(transaction)驱动的协议,会话一旦建立,只要双方不主动发 BYE,dialog 就会无限期存在。 但现实中的失败模式往往是"静默失败"——
这些情况下,网络侧的 SIP 状态无人清理,媒体面 RTP 停流但会话条目悬挂,直接导致端口资源泄漏、错路由、计费超长("幽灵通话"),以及最经典的现网投诉——"通话到第 30 分钟准时断"。
3GPP TS 24.229(《IP multimedia call control protocol based on SIP and SDP》)在 IMS 会话控制中强制要求支持 RFC 4028 定义的 SIP Session Timer 扩展,并依赖它作为会话失活检测的最终兜底机制。其一致性测试规范 TS 34.229-5 第 7.28~7.34 节专门为 5GS 下的会话定时器行为设计了 7 组测试用例(MO/MT、远端支持/不支持/不发 Session-Expires、谁做 refresher 等)。
本文基于 RFC 4028 原文与 3GPP TS 24.229 / TS 34.229-5,逐消息、逐 IE 拆解这套协商-刷新-超时终止的完整信令机制。
Session Timer 的全部控制信息,集中在三个 SIP 头域和一个响应码上:
| 头域 / 响应码 | 出现位置 | 含义 | 取值约束(RFC 4028 §4/§5/§6) |
|---|---|---|---|
| Session-Expires | INVITE/UPDATE 请求及对应 2xx 响应 | 会话最大存活时长(delta-seconds) | 绝对下限 90s;推荐 1800s(30 分钟);可携带 ;refresher=uac/uas 子参数 |
| Min-SE | INVITE/UPDATE 请求;仅 422 响应中携带 | 该端可接受的最小会话时长 | ≥90s;缺省即 90s;响应中只能出现在 422 |
| refresher | Session-Expires 的子参数 | 指定由谁发起周期性刷新 | uac(主叫方刷新)/ uas(被叫方刷新) |
| 422 Session Interval Too Small | UAS 或代理拒绝请求时 | 请求的 Session-Expires 低于本端 Min-SE | 必须携带 Min-SE 告知门槛 |
设计要点解读:
m=mandatory)。它在请求中是"我的底线",在 422 中是"我拒绝你的理由"。下面给出一条典型 MO VoNR 呼叫中,主叫 UE 与被叫之间完整的 Session Timer 协商与中段刷新流程(P-CSCF/S-CSCF 为路由节点,亦参与 Min-SE 校验):
sequenceDiagram
participant UE as 主叫 UE (UAC)
participant PC as P-CSCF
participant SC as S-CSCF
participant TE as 被叫 UE (UAS)
Note over UE,TE: 阶段1:会话建立与SE协商
UE->>PC: INVITE<br/>Session-Expires:1200;refresher=uac<br/>Min-SE:90, Supported:timer
Note right of PC: 本地Min-SE=1800<br/>1200 < 1800 → 拒绝
PC-->>UE: 422 Session Interval Too Small<br/>(Min-SE:1800)
UE->>PC: ACK
UE->>PC: INVITE<br/>Session-Expires:1800, Min-SE:90
PC->>SC: INVITE (透传 SE:1800)
SC->>TE: INVITE
TE-->>UE: 183 Session Progress (早期媒体/编解码协商)
TE-->>PC: 200 OK<br/>Session-Expires:1800;refresher=uac<br/>Require:timer
PC-->>UE: 200 OK
UE->>TE: ACK
Note over UE,TE: 阶段2:会话已建立,SE=1800s<br/>UE为refresher,过半(900s)刷新
Note right of UE: 900s 后发起刷新
UE->>TE: re-INVITE / UPDATE<br/>(Session-Expires:1800)
TE-->>UE: 200 OK (Session-Expires:1800)
UE->>TE: ACK
Note over UE,TE: 过期点延长至本次2xx之后+1800s
Note over UE,TE: 阶段3:刷新失败/超时 → 终止
alt 刷新请求无响应或收到 481/408
UE->>TE: BYE (会话失活,主动清理)
else 过期前从未收到刷新请求
TE->>UE: BYE (对端过期清理)
end
关键 IE 逐消息解析:
① 初始 INVITE——Supported: timer 是会话定时器能力的"广告位",任何支持 timer 的 UA 必须在除 ACK 外的每个请求里都带上(RFC 4028 §7.1)。UE 若希望自己做刷新方,就在 Session-Expires:1200;refresher=uac 中明确;若希望强制对端支持,可加 Require: timer。
② 422 重试——这是 Session Timer 最具特色的协商环节。P-CSCF(或路径上任意代理、或 UAS)发现 1200 < 本地Min-SE(1800),回 422 并 必须 带上自己的 Min-SE:1800。UE 收到后,按 RFC 4028 §7.3:取"所有收到的 422 中最大的 Min-SE"作为下限,重新构造 INVITE。TS 34.229-5 第 7.28 节的测试用例就构造了 连续两次 422(Min-SE:1860 → 1920) 的重试链,验证 UE 最终以 Session-Expires:1920, refresher=uac 完成建立——这条测试线完美刻画了现网中代理逐级抬高门槛的真实场景。
③ 2xx 响应绑定 refresher——最终 200 OK 中的 Session-Expires:1800;refresher=uac 是 绑定(binding) 的:双方依据此值确定"谁刷新、何时过期"。注意 UAS 在 2xx 里只能 减小或保持 SE(不得增大),且不得低于请求中的 Min-SE(或 90s)。
④ 过半刷新——RFC 4028 §9 推荐 refresher 在 会话时长过半(900s) 时发起 re-INVITE/UPDATE。只有 2xx 响应才能延长过期点——这是核心不变式。即使刷新请求被 422 拒绝(对端临时抬高了 Min-SE),原过期点不变,UE 仍须在该过期点前重发刷新请求。
⑤ 终止逻辑——两条独立的失活路径:refresher 发出刷新后一直收不到响应(或收到 408/481)→ refresher 发 BYE;非刷新方在过期点前始终没收到任何刷新请求 → 非刷新方发 BYE。这种双向兜底确保了无论谁先失联,会话最终都会被释放。
谁来做 refresher,不是写死的,而是在会话建立时由 UAS 依据 UAC 能力 + UAC 是否已表态 决定的。RFC 4028 §9 给出了决定性的决策表(Table 2):
flowchart TD
A[收到的 INVITE 中 Supported 含 timer?] -->|否 UAC不支持| R1[refresher = uas<br/>网络/被叫侧负责刷新]
A -->|是 UAC支持| B[INVITE 是否带 refresher 参数?]
B -->|未带 不表态| R2[UAS 自行决定<br/>uas 或 uac]
B -->|带 refresher=uac| R3[refresher = uac<br/>UAS 不可推翻]
B -->|带 refresher=uas| R4[refresher = uas<br/>UAS 不可推翻]
R1 --> RE[2xx 中 Session-Expires<br/>绑定 refresher 参数]
R2 --> RE
R3 --> RE
R4 --> RE
RE --> REQ{refresher == uac ?}
REQ -->|是| F1[2xx 必须带 Require:timer<br/>强制UAC处理响应]
REQ -->|否且UAC支持| F2[2xx 应带 Require:timer<br/>SHOULD 级别]
三条铁律(RFC 4028 §9):
refresher=uac,UAS 只能接受 uac,反之亦然。这是"先到先得"的能力声明机制。Require: timer 的作用是确保响应被对端正确处理:refresher=uac 时是 MUST(因为 UAC 必须从 2xx 里知道"轮到我刷新了"),refresher=uas 且 UAC 支持时是 SHOULD(因为 UAC 虽不刷新,但要负责在收不到刷新时发 BYE)。
IMS 工程意义:P-CSCF 几乎总是路径上第一个"懂事"的 SIP 代理。当 UE(尤其老式终端)不支持 timer 时,P-CSCF 会在 2xx 中插入
Session-Expires;refresher=uas并由自己周期性向对端发起 re-INVITE。一旦 UE 静默失联,P-CSCF 的刷新请求超时,便主动发 BYE,把悬挂的会话连同计费、媒体面一起清掉。
Session Timer 在每个 UA 内部维护一份状态:session interval(时长)+ session expiration(绝对过期时刻)+ refresher 身份,且绑定到具体 dialog。
stateDiagram-v2
[*] --> 协商中: 发送/接收 INVITE
协商中 --> 协商中: 422 → 调整SE后重发INVITE
协商中 --> 协商中: 422重试循环
协商中 --> 已建立: 收到/发出2xx含Session-Expires
协商中 --> [*]: 2xx无Session-Expires → 不启用定时器
已建立 --> 刷新中: 过半SE,refresher发re-INVITE/UPDATE
刷新中 --> 已建立: 2xx响应(过期点向后延展)
刷新中 --> 终止: 481/408/无响应 → refresher发BYE
已建立 --> 终止: 过期前未收到刷新 → 非刷新方发BYE
已建立 --> 终止: 任意一方主动BYE
终止 --> [*]: 释放dialog/媒体/承载
两条最易被忽视的状态规则:
IMS 中有多个"周期性保活"机制,初学者极易混淆。下表厘清它们的边界:
| 机制 | 作用对象 | 触发条件 | 失效后果 | 典型周期 | 规范 |
|---|---|---|---|---|---|
| SIP Session Timer | SIP dialog(单次呼叫会话) | refresher 在过半 SE 时发 re-INVITE/UPDATE | 任一方发 BYE,呼叫释放 | 1800s | RFC 4028 / TS 24.229 |
| IMS 注册周期 | IMS 注册(用户在网状态) | 网络下发的 P-CSCF 定时器到期,UE 周期重注册 | S-CSCF 去注册,用户整体下线 | ~3600s | TS 24.229 / TS 23.228 |
| NAT/OPTIONS keepalive | NAT 绑定(中间盒端口映射) | 周期发空 OPTIONS 或 CRLF | NAT 表项老化,信令不通 | 20~30s | 工程实践(RFC 6223) |
| RTP 媒体保活 | RTP 媒体流连通性 | 周期发空 RTP/舒适噪声包 | 媒体面误判停流,触发媒体检测 | 15~30s | TS 26.114 |
关键区分:注册保活管"用户在不在线",Session Timer 管"这一通电话还活着没"。一个用户可同时有 1 个注册 + N 个并行会话,每个会话独立跑自己的 Session Timer。注册过期会触发 S-CSCF 清理该用户所有会话(这也是 HiCellTek 掉话诊断树里"IMS 注册过期 → S-CSCF 释放会话"的来源),但这是注册层行为,与会话定时器本身的超时是两条独立路径。
用 Wireshark 过滤 SIP,按以下特征定位:
sip.Session-Expires 或显示过滤器 sip.Header contains "Session-Expires"。看 INVITE 与 2xx 中 SE 值是否一致、refresher 取值。sip.Status-Code == 422,展开响应看 Min-SE 值——这是排查"为什么 SE 被改"的关键证据。Session-Expires 续期,即为刷新请求。sip.Method == "BYE",结合时间戳判断是否恰好在 SE 过期点附近,并在 Reason 头或前序 408/481 中寻找线索。故障一:通话到第 30 分钟准时断(最经典)。 telecomHall 论坛反复出现的案例:VoLTE 呼叫固定在 30 分钟断。根因即 Session Timer。排查路径:抓包确认 SE 值(多为 1800s)→ 确认刷新请求是否在 ~900s 准时发出 → 检查刷新请求是否被对端拒绝(常见于 NAT 老化导致刷新请求到不了被叫,或被 SBC 因 SDP 不变而丢弃)。若刷新请求根本没发,则检查 refresher 角色判定——可能双方都误以为对方是 refresher("双方都不刷新"),到期双双发 BYE。
故障二:refresher 不匹配 / 双方都不刷新。
违反 Table 2 的实现会导致:UAC 写了 refresher=uac,但 UAS 错误地改成 uas 并把自己设为非刷新方;或一方当 uas、一方当 uac 的理解不一致。结果双方都"等对方刷新",SE 到期一起发 BYE。排错:逐跳对比 INVITE 与 2xx 中的 Session-Expires 头,确认 refresher 参数未被中间代理擅自篡改(P-CSCF/SBC 改写 SE 是合规的,但改 refresher 角色需遵循 Table 2)。
故障三:422 死循环。 若 UAC 的 Session-Expires 永远低于路径上某节点的 Min-SE,且该节点在每次重试中不断抬高 Min-SE,会陷入 INVITE→422→INVITE→422 的死循环(TS 34.229-5 §7.28 测试链即模拟此)。规范要求 UAC 取"所有 422 中最大的 Min-SE"且 Min-SE 有 90s 下限、SE 有推荐 1800s,正常应能收敛。死循环通常是某 SBC 的 Min-SE 配置异常(如设成天文数字)或 UAC 实现未正确取最大值。Sansay TAC 文档记录的"408 refresh failure"也常源于刷新请求本身被中间设备超时丢弃。
Q1:Session Timer 和 precondition、PRACK 是一回事吗? A:完全不同。precondition(RFC 3312)解决的是"资源/QoS 就绪前不响铃"的本地/远端资源确认,靠 183+PRACK 传递 SDP 状态属性;PRACK(RFC 3262, 100rel)解决临时响应的可靠传输。Session Timer(RFC 4028)解决的是"会话存活的周期性确认与失活清理"。三者都借助 re-INVITE/UPDATE 这类 mid-dialog 请求,但目标各异,可叠加使用。
Q2:refresher=uac 和 uas,网络通常希望谁做? A:在 IMS 中,网络(P-CSCF/SBC)倾向于自己做 refresher(即对 UE 而言是 uas 角色),以便在 UE 静默失联时由网络主动检测并清理。但若 UE 能力强且省电敏感,也可让 UE 做 uac 刷新。最终取决于 Table 2 的协商结果与运营商策略。
Q3:刷新请求里 SDP 不变(纯保活),为什么还要做完整 offer/answer? A:因为 re-INVITE/UPDATE 本质是会话修改请求,规范要求其按正常 offer/answer 流程处理。为避免媒体重协商抖动,刷新请求通常发送与当前会话一致的 SDP("no-op" offer),对端回一致 answer。一些 SBC 会识别这种无变化的刷新并做快速处理。
Q4:会话过期后发的 BYE,与正常挂断 BYE 在信令上有区别吗?
A:方法都是 BYE,但超时触发的 BYE 常携带 Reason 头(如 Reason:SIP;cause=408 或 cause=200;text="Session Timer Expires"),且在时间上严格出现在 SE 过期点附近,前序通常有失败/无响应的刷新请求记录。抓包时按时间轴对齐即可区分。
Q5:5G VoNR 与 VoLTE 在 Session Timer 上有差异吗? A:信令机制完全一致(都跑在 IMS SIP 层)。差异在承载:VoNR 的语音承载是 5QI=1 的 5GS PDU 会话,RLF 后无线恢复更快,但若 UE 真正失联,P-CSCF 的 Session Timer 仍是最终兜底。5G 侧 TS 34.229-5 §7.28~7.34 的测试用例就是专门为 5GS 场景设计的。
本文由「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 等场景全覆盖。
