session timer(一)

本文介绍了SIP协议中会话存活机制的工作原理及其相关参数。由于SIP本身并未定义会话存活机制,导致代理服务器难以判断会话状态。RFC4028为此引入了一种机制,通过周期性发送re-INVITE或UPDATE请求维持会话,避免因BYE消息丢失导致的问题。

功能介绍

          SIP并没有为所建立的会话定义存活机制。

虽然用户代理能够通过会话特定的机制推断会话是否超时,可是代理server却做不到这点。

如此一来。代理server有时会无法推断会话是否还是活动的。

比如,当一个用户代理在会话结束时发送BYE消息失败,或者因为网络问题BYE消息丢失,代理server将不会知道会话已经结束。在这样的情况下,代理server将保持呼叫的状态而且无法知道呼叫状态信息何时失效。

     为了解决问题,RFC4028SIP会话定义了一种存活机制。用户代理或代理server周期性发送re-INVITEUPDATE请求用来保持会话的活动。会话更新请求的间隔通过其定义的协商机制决定。

假设在间隔内没有收到会话更新请求,该会话被觉得已经终止。

工作原理 

    UAC通过INVITE消息发起,这个消息包含一个带有可选标签“timer”的Supported头字段,用来表明支持Session Timer功能。该请求通过代理server传递,所经过的任代理server都能够根据他们的兴趣建立会话定时器。每一个代理server都能够在请求中插入一个Session-Expires头字段和一个Min-SE头字段(前提是请求中还没有这些字段),或者改动上述已存在头字段的值。

    Min-SE头字段为会话更新间隔建立最小刷新时间。

这个头字段的目的是防止怀有恶意的代理server设置随意短的更新间隔以致它的邻居代理负荷超载。

处理请求的每一个代理server能够提高这个下限(实际上就是提高刷新的周期),可是不能减少下限。

 

    Session-Expires头字段为会话更新间隔建立最长刷新时间。不论什么服务于该请求的代理能够减少这个值。但必须大于Min-SE头字段指定的值。

    假设Session-Expires的间隔太小(小于代理server要维护的Min-SE头字段的值)。那么代理server将拒绝这个请求并返回一个422响应。该响应包括一个Min-SE头字段表明它所支持的最小会话间隔。UAC再次尝试发送请求。这次请求中包括了Min-SE头字段,头字段等于先前接收到的全部422响应中最大的Min-SE头字段。

这样一来。最小定时器就能满足所经过的全部代理server的约束条件。 

    在几次INVITE/422消息的重复传送后,请求终于到达UASUAS能够调整会话间隔的值就好像它自己也是一个代理server。

之后。它将这个终于的会话间隔增加2xx响应的Session-Expires头字段。

Session-Expires头字段还包括一个“refresher”參数用来表示更新的运行者(是当前的UAC还是UAS)。当2xx响应沿代理server返回时,不论什么代理server能够观察这个终于的会话间隔但不能改动它。

    通过响应中的Session-Expires头字段,UACUAS都知道会话定时器是活动的。它何时终止以及谁在更新会话。在终止前的某个时刻,当前活动的更新者生成一个会话更新请求,能够是一个re-INVITE或者UPDATE请求。

假设更新者始终得不到这个会话更新请求的响应,它就会发送一个BYE消息结束会话。相同。假设还有一端在会话终止前始终收不到会话更新请求。它也会发送一个BYE消息结束会话。

相关參数

       Session-Expires头字段用于传达SIP会话的会话间隔。该字段仅仅包括在INVITEUPDATE请求。也包括在INVITEUPDATE消息的不论什么一个2xx响应中。

当在已经协商确定Session-Expires,那么该会话将在Session-Expires/2的时间进行会话更新,该更新方式能够是re-INVITE或者UPDATE的请求。

        Min-SE头字段表示会话间隔的最小值。以秒为单位。

当它被用在INVITEUPDATE请求中时。用来表示该会话所要使用的会话间隔的最小值。

        422回应代码出如今会话协商过程中,当Session-Expires的间隔太小(小于UAS所支持的Min-SE头字段的值)时。UAS将回应要求UAC又一次协商





<think>我们正在讨论SIP协议中的OPTIONS方法以及与之相关的计时器(Timer)。在SIP(Session Initiation Protocol)中,OPTIONS方法用于查询服务器的能力。客户端可以发送OPTIONS请求来了解服务器支持的方法、内容类型、扩展等信息,而不发起个会话。 关于“SIP OPTION Timer”,可能指的是与OPTIONS请求相关的计时器。在SIP中,计时器用于控制请求的重传。根据RFC3261,SIP消息在传输层(如UDP)上使用重传机制来保证可靠性。对于每个请求,客户端都会启动组计时器来控制重传行为。 具体到OPTIONS请求,它使用与INVITE请求相同的重传机制,但有个例外:INVITE请求在2xx响应后停止重传,而其他请求(包括OPTIONS)在最终响应(即非1xx响应)后停止重传。 SIP中定义了几个重要的计时器(在RFC3261的17节中描述): - T1: 估计的往返时间(RTT),默认为500ms。它是初始重传时间。 - T2: 最大重传间隔,默认为4s。对于非INVITE请求,重传时间间隔从T1开始,每次翻倍,直到达到T2,之后以T2的时间间隔重传。 - Timer A(重传计时器):初始值为T1,每次重传后翻倍(直到达到T2)。 - Timer B:超时后触发事务超时错误,默认值为64*T1=32s。 对于非INVITE请求(如OPTIONS),客户端事务状态机使用以下计时器: - 当发送请求时,启动Timer A(初始T1)和Timer B(64*T1)。 - 如果Timer A超时,则重传请求,并将Timer A的时间翻倍(但不超过T2),然后重启Timer A。 - 如果Timer B超时,则事务超时,向上层报告。 因此,对于OPTIONS请求,计时器的行为如下: 1. 客户端发送OPTIONS请求,启动Timer A(初始为T1)和Timer B(64*T1)。 2. 如果在Timer A超时前收到临时响应(1xx),则停止Timer A,并启动Timer D(在非INVITE请求中,Timer D用于等待最终响应,其值至少为32秒,但实际中通常设置为64*T1)。 3. 如果没有收到临时响应,那么当Timer A超时,重传请求,并重置Timer A为min(2*前个值, T2)。同时,Timer B仍然在运行。 4. 当收到个最终响应(2xx-6xx)时,客户端事务停止Timer A和Timer B,并将响应传递给上层。 5. 如果Timer B超时,则事务超时,客户端会向上层报告个超时错误。 注意:在UDP传输中,重传是必要的。如果使用TCP或TLS,则不需要重传,因为传输层提供了可靠性。 代码示例:由于SIP协议栈通常由专门的库实现,这里我们不会从头实现个SIP事务层。但是,我们可以用伪代码描述OPTIONS请求的重传逻辑。 ```python import time import random # 假设的全局常量 T1 = 0.5 # 500ms T2 = 4 # 4s TIMER_B = 64 * T1 # 32s class SIPClientTransaction: def __init__(self, request, transport): self.request = request self.transport = transport self.state = "TRYING" self.retransmit_count = 0 self.timer_a = None self.timer_b = None self.timer_d = None def start_timers(self): # 启动Timer A和Timer B self.schedule_timer_a(T1) self.schedule_timer_b(TIMER_B) def schedule_timer_a(self, interval): # 模拟设置定时器A,实际中可能使用事件循环或线程定时器 self.timer_a = (time.time(), interval) def schedule_timer_b(self, interval): self.timer_b = (time.time(), interval) def schedule_timer_d(self): # Timer D用于等待最终响应,在非INVITE事务中,当收到临时响应时启动 self.timer_d = (time.time(), TIMER_B) # 实际中Timer D的值至少32秒 def handle_timeout(self, timer_name): if timer_name == 'A': # 重传请求 if self.retransmit_count < 10: # 防止无限重传,但实际中由Timer B控制 self.transport.send(self.request) self.retransmit_count += 1 next_interval = min(2 * self.timer_a[1], T2) self.schedule_timer_a(next_interval) elif timer_name == 'B': # Timer B超时,事务失败 self.state = "TERMINATED" self.notify_application("Timeout") elif timer_name == 'D': # Timer D超时,事务失败 self.state = "TERMINATED" self.notify_application("Timeout") def process_response(self, response): if response.is_provisional(): # 1xx响应 # 停止Timer A,启动Timer D self.timer_a = None self.schedule_timer_d() elif response.is_final(): # 2xx-6xx # 停止所有计时器 self.timer_a = None self.timer_b = None self.timer_d = None self.state = "COMPLETED" self.notify_application(response) # 其他处理... # 模拟时间推进,检查定时器 def check_timers(self, current_time): if self.timer_a: start, interval = self.timer_a if current_time - start >= interval: self.handle_timeout('A') if self.timer_b: start, interval = self.timer_b if current_time - start >= interval: self.handle_timeout('B') if self.timer_d: start, interval = self.timer_d if current_time - start >= interval: self.handle_timeout('D') def notify_application(self, message): # 通知应用层 pass # 模拟运行 if __name__ == "__main__": # 创建事务并启动 transaction = SIPClientTransaction("OPTIONS sip:example.com SIP/2.0", "udp") transaction.start_timers() # 模拟时间循环 start_time = time.time() while time.time() - start_time < 40: # 模拟运行40秒 current_time = time.time() transaction.check_timers(current_time) # 这里应该包括接收响应的逻辑,但为了简化,我们省略了 time.sleep(0.1) ``` 注意:上述代码是概念性的,用于说明计时器在SIP OPTIONS事务中的行为。在实际的SIP实现中,定时器通常由事件循环或操作系统定时器管理。 解释: - 我们定义了个`SIPClientTransaction`类来处理OPTIONS请求的事务状态。 - 事务启动时,设置Timer A和Timer B。 - 在`check_timers`方法中,我们检查每个定时器是否超时,如果超时则触发相应的处理。 - 当收到临时响应(1xx)时,停止Timer A并启动Timer D(在非INVITE事务中,Timer D用于等待最终响应,其值至少为32秒)。 - 当收到最终响应时,停止所有定时器。 请注意,实际SIP协议栈的实现要复杂得多,包括处理不同传输层、解析消息、路由等。这里仅关注计时器部分。 相关问题: §§相关问题§§: 1. SIP OPTIONS方法的主要用途是什么? 2. 在SIP协议中,除了OPTIONS方法,还有哪些常用的方法? 3. 在SIP中,INVITE事务和非INVITE事务在计时器处理上有何不同? 4. 如何使用SIP的OPTIONS方法实现心跳机制?</think>### SIP OPTION Timer 详解 在 SIP(Session Initiation Protocol)协议中,OPTIONS Timer 是用于控制 OPTIONS 请求重传行为的计时器机制。OPTIONS 请求用于查询服务器能力(如支持的方法、编解码器等),而计时器确保在不可靠传输(如 UDP)下的可靠性。 #### 核心计时器机制 根据 RFC 3261 标准,OPTIONS 请求使用以下计时器: 1. **Timer A(重传计时器)**: - 初始值:T1(默认 500ms) - 指数退避重传:每次翻倍(T1 → 2T1 → 4T1...) - 上限:T2(默认 4s) 2. **Timer B(事务超时计时器)**: - 固定值:64 × T1(默认 32s) - 超时则终止事务并报告失败 3. **Timer D(等待最终响应计时器)**: - 当收到 1xx 临时响应时启动 - 值 ≥ 32s(实际实现多为 64 × T1) #### Python 模拟实现 ```python import time import random # RFC 3261 默认计时器常量 T1 = 0.5 # 500ms T2 = 4 # 4s TIMER_B = 64 * T1 # 32s class SIPOptionsTransaction: def __init__(self, target): self.target = target self.retransmit_count = 0 self.last_sent_time = 0 self.next_retransmit = 0 self.state = "TRYING" self.response_received = False def send_options(self): """发送 OPTIONS 请求""" print(f"[{time.time():.1f}] Sending OPTIONS to {self.target}") self.last_sent_time = time.time() self._schedule_retransmit(T1) # 初始重传时间 T1 self._start_timer_b() # 启动事务超时计时器 def _schedule_retransmit(self, interval): """设置下次重传时间""" self.next_retransmit = self.last_sent_time + interval print(f" ├─ Scheduled retransmit at T={self.next_retransmit:.1f}") def _start_timer_b(self): """启动事务超时计时器""" self.timer_b_expiry = time.time() + TIMER_B print(f" ├─ Timer B set to {TIMER_B}s (expiry T={self.timer_b_expiry:.1f})") def handle_timeout(self): """处理超时事件""" current_time = time.time() # 检查 Timer B 超时 if current_time >= self.timer_b_expiry: print(f"[{current_time:.1f}] !!! Timer B expired. Transaction failed.") self.state = "TERMINATED" return True # 检查重传超时 if not self.response_received and current_time >= self.next_retransmit: self.retransmit_count += 1 print(f"[{current_time:.1f}] Retransmit #{self.retransmit_count} to {self.target}") # 指数退避计算下次重传时间 next_interval = min(T1 * (2 ** self.retransmit_count), T2) self._schedule_retransmit(next_interval) self.last_sent_time = current_time return False def handle_response(self, status_code): """处理服务器响应""" current_time = time.time() print(f"[{current_time:.1f}] Received {status_code} response") if 100 <= status_code < 200: # 1xx 临时响应 if not hasattr(self, 'timer_d_start'): print(" ├─ Starting Timer D (min 32s)") self.timer_d_start = current_time return False if status_code >= 200: # 最终响应 self.response_received = True print(f" ├─ Transaction completed in {current_time - self.last_sent_time:.1f}s") self.state = "COMPLETED" return True return False # 模拟运行 def simulate_sip_transaction(): print("=== SIP OPTIONS Transaction Simulation ===") transaction = SIPOptionsTransaction("sip:server.example.com") transaction.send_options() start_time = time.time() while time.time() - start_time < 35: # 模拟运行35秒 current_time = time.time() # 随机生成服务器响应(模拟网络延迟) if not transaction.response_received and random.random() < 0.2: if transaction.handle_response(200): break # 检查超时事件 if transaction.handle_timeout(): break time.sleep(0.1) # 模拟时间推进 print(f"Final state: {transaction.state}") if __name__ == "__main__": simulate_sip_transaction() ``` #### 代码解释: 1. **计时器机制**: - `Timer A`:通过 `_schedule_retransmit()` 实现指数退避重传 - `Timer B`:在 `_start_timer_b()` 中设置 32s 绝对超时 - `Timer D`:收到 1xx 响应时隐式启动(实际实现需维护独立计时器) 2. **状态管理**: - `TRYING`:等待响应状态 - `COMPLETED`:收到最终响应 - `TERMINATED`:Timer B 超时 3. **典型输出**: ``` === SIP OPTIONS Transaction Simulation === [1710000000.0] Sending OPTIONS to sip:server.example.com ├─ Scheduled retransmit at T=1710000000.5 ├─ Timer B set to 32.0s (expiry T=1710000032.0) [1710000000.5] Retransmit #1 to sip:server.example.com ├─ Scheduled retransmit at T=1710000001.5 [1710000001.5] Retransmit #2 to sip:server.example.com ├─ Scheduled retransmit at T=1710000003.5 [1710000003.5] Retransmit #3 to sip:server.example.com ├─ Scheduled retransmit at T=1710000007.5 [1710000005.0] Received 200 response ├─ Transaction completed in 3.5s Final state: COMPLETED ``` #### 关键行为: 1. **重传机制**: - 若无响应,在 T1(0.5s)→T2(4s) 间隔重传 - 达到 T2 后保持 4s 间隔重传 2. **超时控制**: - Timer B:32s 后强制终止事务 - Timer D:收到临时响应后至少等待 32s 3. **终止条件**: - 收到 2xx/3xx/4xx/5xx/6xx 最终响应 - Timer B 超时(网络故障或服务器无响应) #### 实际应用场景: 1. **服务发现**:客户端定期发送 OPTIONS 查询服务器状态 2. **NAT 保活**:通过 OPTIONS 保持 UDP NAT 映射 3. **负载均衡检测**:健康检查服务器可用性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值