15. 终止会话 (Terminating a Session)
本节描述终止由SIP建立的会话的程序。会话的状态和对话的状态密切相关。当使用INVITE发起会话时, 来自不同UAS的每个1xx或2xx响应都会创建一个对话, 如果该响应完成了提供/应答交换, 它还会创建一个会话。因此, 每个会话都与单个对话"关联" - 即导致其创建的对话。如果初始INVITE生成非2xx最终响应, 则会终止通过对请求的响应创建的所有会话 (如果有) 和所有对话 (如果有)。通过完成事务, 非2xx最终响应还可以防止由于INVITE而创建更多会话。
BYE请求用于终止特定会话或尝试的会话。 在这种情况下, 特定会话是与对话另一侧的对等UA的会话。当在对话上接收到BYE时, 与该对话关联的任何会话都应该终止。UA不得在对话外发送BYE。呼叫方的UA可以为已确认或早期对话发送BYE, 被叫方的UA可以在已确认的对话上发送BYE, 但不得在早期对话上发送BYE。
但是, 被叫方的UA在收到对其2xx响应的ACK或服务器事务超时之前, 不得在已确认的对话上发送BYE。如果没有SIP扩展定义与对话关联的其他应用层状态, BYE也会终止对话。
对INVITE的非2xx最终响应对对话和会话的影响使得使用CANCEL很有吸引力。CANCEL尝试强制对INVITE的非2xx响应 (特别是487)。因此, 如果UAC希望完全放弃其呼叫尝试, 它可以发送CANCEL。如果INVITE导致对INVITE的2xx最终响应, 这意味着UAS在CANCEL进行期间接受了邀请。UAC可以继续任何2xx响应建立的会话, 或者可以使用BYE终止它们。
"挂断"的概念在SIP中没有很好地定义。 它特定于一个特定的 (尽管常见的) 用户界面。通常, 当用户挂断时, 它表示希望终止建立会话的尝试, 并终止已经创建的任何会话。对于呼叫方的UA, 如果初始INVITE尚未生成最终响应, 这将意味着CANCEL请求, 并且在最终响应后对所有已确认的对话发送BYE。对于被叫方的UA, 它通常意味着BYE; 据推测, 当用户拿起电话时, 生成了2xx, 因此挂断将在收到ACK后导致BYE。这并不意味着用户不能在收到ACK之前挂断, 它只是意味着他电话中的软件需要短暂维护状态以便正确清理。如果特定UI允许用户在应答之前拒绝呼叫, 403 (Forbidden) 是表达这一点的好方法。根据上述规则, 不能发送BYE。
15.1 使用BYE请求终止会话 (Terminating a Session with a BYE Request)
15.1.1 UAC行为 (UAC Behavior)
BYE请求的构造与对话内的任何其他请求一样, 如第12节所述。
一旦构造了BYE, UAC核心创建一个新的非INVITE客户端事务, 并将BYE请求传递给它。UAC必须在BYE请求传递给客户端事务后立即将会话视为已终止 (因此停止发送或监听媒体)。如果BYE的响应是481 (Call/Transaction Does Not Exist) 或408 (Request Timeout), 或者根本没有收到BYE的响应 (即, 客户端事务返回超时), UAC必须将会话和对话视为已终止。
15.1.2 UAS行为 (UAS Behavior)
UAS首先根据第8.2节中描述的通用UAS处理来处理BYE请求。接收BYE请求的UAS核心检查它是否与现有对话匹配。如果BYE与现有对话不匹配, UAS核心应该生成481 (Call/Transaction Does Not Exist) 响应并将其传递给服务器事务。
此规则意味着UAC发送的不带标签的BYE将被拒绝。这是RFC 2543的更改, RFC 2543允许不带标签的BYE。
接收现有对话的BYE请求的UAS核心必须遵循第12.2.2节的程序来处理请求。完成后, UAS应该终止会话 (因此停止发送和监听媒体)。它可以选择不终止的唯一情况是多播会话, 即使对话中的另一个参与者已终止其在会话中的参与, 参与也是可能的。无论是否结束其在会话中的参与, UAS核心必须为BYE生成2xx响应, 并且必须将其传递给服务器事务进行传输。
UAS必须仍然响应为该对话接收的任何挂起的请求。建议为这些挂起的请求生成487 (Request Terminated) 响应。
BYE请求流程
会话正在进行
UAC UAS
| |
|<=========媒体流===================>|
| |
|---BYE----------------------------->|
| (立即停止媒体) |
| | (处理BYE)
| | (停止媒体)
|<--200 OK---------------------------|
| |
会话和对话终止 会话和对话终止
CANCEL vs BYE
| 特性 | CANCEL | BYE |
|---|---|---|
| 用途 | 取消挂起的INVITE | 终止已建立的会话 |
| 对话状态 | 对话外或早期对话 | 已确认的对话 |
| 效果 | 阻止会话建立 | 终止现有会话 |
| 发送时机 | INVITE尚未收到最终响应 | 会话已建立 |
| 响应 | 由代理或UAS响应 | 由对话对等方响应 |
| 媒体 | 不影响 (还没有媒体) | 立即停止媒体 |
挂断场景分析
场景1: 呼叫方在振铃时挂断
UAC UAS
|---INVITE--------------------------->|
|<--180 Ringing----------------------|
| (用户挂断) |
|---CANCEL--------------------------->|
|<--200 OK (对CANCEL)-----------------|
|<--487 Request Terminated (对INVITE)-|
|---ACK----------------------------->|
结束
场景2: 呼叫方在通话中挂断
UAC UAS
| |
|<=========媒体流===================>|
| (用户挂断) |
|---BYE----------------------------->|
|<--200 OK---------------------------|
结束
场景3: 被叫方在应答前拒绝
UAC UAS
|---INVITE--------------------------->|
|<--180 Ringing----------------------|
| | (用户拒绝)
|<--403 Forbidden--------------------|
|---ACK----------------------------->|
结束
场景4: 被叫方在通话中挂断
UAC UAS
| |
|<=========媒体流===================>|
| | (用户挂断)
|<--BYE------------------------------|
|---200 OK--------------------------->|
结束
特殊情况处理
1. 被叫方在收到ACK前不能发送BYE
UAC UAS
|---INVITE--------------------------->|
|<--200 OK---------------------------|
| | ❌ 不能发送BYE
| | (必须等待ACK)
|---ACK----------------------------->|
| | ✅ 现在可以发送BYE
2. 早期对话的限制
呼叫方:
✅ 可以在早期对话发送BYE
被叫方:
❌ 不能在早期对话发送BYE
✅ 应该使用非2xx响应拒绝
3. 多播会话
场景: 多播会议
- 收到BYE后, UAS可以选择继续参与多播会话
- 即使对话中的对等方离开, 会话仍可继续
- UAS仍然必须发送200 OK响应BYE
重要注意事项
-
立即停止媒体: UAC在发送BYE后立即停止媒体, 不等待响应。
-
对话终止: BYE通常同时终止会话和对话 (除非有其他应用层状态)。
-
必须在对话内: BYE必须在现有对话内发送, 不能在对话外发送。
-
被叫方限制: 被叫方在收到ACK之前不能发送BYE。
-
早期对话: 被叫方不能在早期对话上发送BYE, 应该使用非2xx响应。
-
481响应: 如果BYE不匹配任何对话, 返回481响应。
-
挂起请求: 收到BYE后, UAS必须响应该对话的所有挂起请求, 建议使用487。
-
超时处理: 如果BYE超时或收到481/408, UAC仍然认为会话已终止。
BYE请求示例
BYE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds10
Max-Forwards: 70
From: Alice <sip:[email protected]>;tag=1928301774
To: Bob <sip:[email protected]>;tag=a6c85cf
Call-ID: [email protected]
CSeq: 231 BYE
Content-Length: 0
BYE响应示例
SIP/2.0 200 OK
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds10
;received=192.0.2.1
From: Alice <sip:[email protected]>;tag=1928301774
To: Bob <sip:[email protected]>;tag=a6c85cf
Call-ID: [email protected]
CSeq: 231 BYE
Content-Length: 0
会话生命周期完整流程
1. 发起会话 (INVITE)
├─ 临时响应 (1xx) - 早期对话
└─ 最终响应 (2xx) - 已确认对话
2. 会话建立
└─ ACK
3. 媒体交换
└─ RTP/RTCP等
4. (可选) 修改会话 (re-INVITE)
├─ 添加/删除媒体
├─ 更改参数
└─ ACK
5. 终止会话
├─ BYE (如果会话已建立)
├─ CANCEL (如果还在振铃)
└─ 非2xx响应 (如果拒绝邀请)
6. 会话和对话结束
本章小结:
第15章描述了如何使用BYE方法终止SIP会话。BYE是在已建立的对话内发送的请求, 用于终止会话和关联的对话。关键要点包括: UAC在发送BYE后立即停止媒体、被叫方在收到ACK之前不能发送BYE、早期对话的特殊限制, 以及BYE与CANCEL的区别。理解会话终止机制对于实现完整的SIP会话生命周期管理至关重要。第13-15章共同构成了SIP会话的完整生命周期: 发起 (INVITE)、修改 (re-INVITE) 和终止 (BYE)。