<!-- title: IMS会话定时器刷新机制拆解 -->
<!-- domain: ims -->

# IMS会话定时器（Session Timer）刷新与失活检测机制深度拆解

## 一、为什么需要 Session Timer：SIP 状态悬挂的"清道夫"

在 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 就会无限期存在。** 但现实中的失败模式往往是"静默失败"——

- UE 驶入地下车库，无线链路瞬间中断，UE 根本来不及发 BYE；
- 电池耗尽或终端崩溃；
- 5G 空口 RLF（Radio Link Failure）后，NAS 信令连接断开，但 SMF/UPF 的 PDU 会话与 IMS 注册状态仍在；
- 漫游场景下中间 SBC 与 UE 之间的 NAT 绑定悄悄老化。

这些情况下，**网络侧的 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 拆解这套协商-刷新-超时终止的完整信令机制。

## 二、三个核心 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 告知门槛 |

设计要点解读：

1. **为什么下限是 90 秒？** RFC 4028 §4 明确解释：90 秒略大于 SIP 事务在超时重传情况下的最坏耗时（约 T1×64≈32s 的两倍）。这样保证刷新方能在 **会话过半（halfpoint）** 时发起一次刷新，且该事务有充裕时间在会话过期前正常完成。
2. **为什么推荐 30 分钟？** 因为统计上 95% 的电话通话时长短于 30 分钟。过短的 SE 会带来"刷新风暴"与双方同时发起 re-INVITE 的 **glare（碰撞）** 问题，损伤网络。
3. **Min-SE 只在 422 中出现**，这是协议级别的硬约束（Table 1 中 422 列为 `m`=mandatory）。它在请求中是"我的底线"，在 422 中是"我拒绝你的理由"。

## 三、完整信令时序：协商 → 422 重试 → 过半刷新 → 超时 BYE

下面给出一条典型 MO VoNR 呼叫中，主叫 UE 与被叫之间完整的 Session Timer 协商与中段刷新流程（P-CSCF/S-CSCF 为路由节点，亦参与 Min-SE 校验）：

```text
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 角色协商算法：RFC 4028 Table 2 精解

谁来做 refresher，不是写死的，而是在会话建立时由 **UAS 依据 UAC 能力 + UAC 是否已表态** 决定的。RFC 4028 §9 给出了决定性的决策表（Table 2）：

```mermaid
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）：

1. **UAS 不能推翻 UAC 已表态的角色。** 若 UAC 写了 `refresher=uac`，UAS 只能接受 `uac`，反之亦然。这是"先到先得"的能力声明机制。
2. **当 UAC 支持但未表态时，UAS 拥有选择权。** 这给被叫网络一个灵活点——例如被叫是 PSTN 网关时，MGCF 可指定由更可靠的 IP 侧做刷新。
3. **当 UAC 完全不支持 timer 时，refresher 必为 uas。** 这正是 IMS 中 P-CSCF 强制启用会话定时器的理论依据——UE 不支持，网络来兜底。

`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。

```mermaid
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/媒体/承载
```

两条最易被忽视的状态规则：

- **"只有 2xx 才延长会话"**：这意味着 1xx 临时响应、甚至失败的刷新尝试都不会续命。一个被 422 反复拒绝的刷新请求，会让会话在原过期点准时死亡——这是很多"刷新失败导致掉话"的根因。
- **"过期时刻 = 最后一次 2xx 发送时刻 + session interval"**：刷新成功后过期点整体后移，而非从原点累加。

## 六、横向对比：Session Timer 与其他周期性机制

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 释放会话"的来源），但这是注册层行为，与会话定时器本身的超时是两条独立路径。

## 七、抓包识别与排错实战

### 7.1 如何在 Wireshark 中识别 Session Timer 流程

用 Wireshark 过滤 SIP，按以下特征定位：

1. **建立阶段**：`sip.Session-Expires` 或显示过滤器 `sip.Header contains "Session-Expires"`。看 INVITE 与 2xx 中 SE 值是否一致、refresher 取值。
2. **422 协商**：`sip.Status-Code == 422`，展开响应看 `Min-SE` 值——这是排查"为什么 SE 被改"的关键证据。
3. **中段刷新**：会话建立后数百秒出现的 re-INVITE 或 UPDATE，且其 CSeq 序号递增、`Session-Expires` 续期，即为刷新请求。
4. **超时 BYE**：`sip.Method == "BYE"`，结合时间戳判断是否恰好在 SE 过期点附近，并在 Reason 头或前序 408/481 中寻找线索。

### 7.2 三大经典故障与排错思路

**故障一：通话到第 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 场景设计的。

## 参考来源

1. [RFC 4028: Session Timers in the Session Initiation Protocol (SIP)](https://www.rfc-editor.org/rfc/rfc4028) — Donovan & Rosenberg, IETF Standards Track，§4 Session-Expires、§5 Min-SE、§6 422、§9 Table 2 UAS refresher 协商算法
2. [3GPP TS 24.229 — IP multimedia call control protocol based on SIP and SDP](https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1055) — IMS 会话控制中强制支持 RFC 4028 会话定时器
3. [3GPP TS 34.229-5 — IMS Client conformance (5GS)](https://www.3gpp.org/ftp/Specs/archive/34_series/34.229-5/) — §7.28~7.34 Session Timer 一致性测试用例（MO/MT、422 重试链 1860→1920、TS 24.167 Session_Timer_Support）
4. [Cisco — Troubleshoot Session Refresh on CUBE](https://www.cisco.com/c/en/us/support/docs/unified-communications/unified-border-element/213843-troubleshoot-session-refresh-on-cube.pdf) — CUBE 侧刷新失败与 refresher 行为实战排错
5. [telecomHall — VoLTE calls dropping after 30 minutes](https://www.telecomhall.net/t/volte-calls-dropping-after-30-minutes/28227) — 经典 30 分钟掉话社区诊断，印证 SE=1800s 兜底释放

---
> 本文由「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 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
