Dialog是SIP中的一个关键概念。根据RFC3261,会话是两个UA之间持续一段时间的点到点的SIP连接,即是记录两者已经连接上的相关内容实体,方便在对话中请求进行识别和处理。
对话都是有对话ID来标识的,包括Call-ID,一个本地标签(From-tag)和一个远端标签(To-tag)。即是说三者确定了某个对话的存在。
对话中还包括一些对话中的后续消息所需的状态,包括:对话ID、本地序列号、远端序列号、本地URI、远端目的、布尔型标记“secure”和路由集。路由集是一个顺序的URI集,指定发送请求到目的地所需遍历的服务器地址。
会话的状态有初始状态和确认状态。当临时的相应被创建时,即标记对话的三个因素刚齐全时为初始状态;而收到2**的最后响应到达时转为确认状态,如果是其他响应或无响应到达,初始状态终结。
如下所示
图1-1 对话建立过程
1. 创建对话
1) UAS
i. 路由集由请求的Record-Route头字段提供,并要保留顺序和URI参数,实时更新,如果下一轮的请求中无Record-Route头字段,则路由集变为空
ii. 本地URI填入回应的Contact头字段
iii.布尔型标记“secure”,如果请求基于TLS(传输层安全协议),则由Request-URI中的secure参数来提供
iv. 远端目的由请求的Request-URI提供
v. From-tag可能不存在,则默认为空
2) UAC
i. 路由集必须为响应消息中的Record-Route头字段的URI列表,保持相反的顺序和保留所有的URI参数
ii. 远端目的为响应消息的Contact头字段的URI
iii. 本地序列号为请求消息的CSeq头字段的序列号值
iv. 远端序列号必须为空,当远端UA发送一个本次对话中的请求后该值才能确定
v. To-tag可能不存在,则默认为空
2. 对话中的请求
对话创建后,UA方可能需要建立新的事务,这时发起请求的UA为UAC,这可能跟对话创建之时的角色不同。re-INVITE是一种对话中修改目的URI的重新请求。
1) UAC行为
i. 发起请求
一个对话中的请求消息有对话所保存的状态信息来构建。
1. 请求消息的To头字段的URI必须设置为对话状态的远端URI
2. 请求消息的To头字段的标签值设置为对话ID的远端标签值
3. 请求消息的From头字段的URI必须设置为对话状态的本端URI
4. 请求消息的From头字段的标签值设置为对话ID的本端标签值
5. 请求消息的Call-ID必须设置为对话的Call-ID
而对话中的其它字段同样有限制:
6. CSeq序列号。CSeq是按照各自方向严格增1的值,如果为空则设为初始值。
7. Request-URI由远端目的指定
8. Route由路由集指定,如果路由集为空,则无Route字段。如果路由集的第一个URI中包含lr参数,UAC必须将Request-URI设置为远端目的URI值;如果路由集的第一个URI中不包含lr参数,UAC必须将Request-URI设置为路由集的第一个URI,且不允许去掉任何参数,同时Route头字段在最后增加一个目的URI。
9.Contact。对话中任何一个更新目的的请求消息包含一个Contact头字段,Contact字段内URI为对话的远端目的URI。
如果UAC收到对目的刷新请求消息的2**响应时,UAC必须将对话的远端目的URI设置为存在Contact字段的URI值。如果响应为481(呼叫/事务不存在)或408(请求超时),UAC应该终止对话;在无对方响应时也应该终止对话。
2) UAS行为
i. 如果请求To字段存在标签值。UAS内核会计算与此请求相关的对话标签值,同时与已有的对话标签值比较,如果匹配则为同一个对话中的请求。此时UAS采用与对话外请求消息处理规则相同的流程进行处理;如果不存在匹配的对话,UAS可以拒绝(481)或接受这个请求。
ii.如果远端序列号为空,则设置为请求消息中CSeq字段的序列号值;如果远端序列号存在并大于请求的CSeq序列号值,则认为请求次序颠倒,回500(服务器内不出错)消息。
3. 终止对话
初始状态的对话不依赖于发起请求的具体方法,只要收到一个非2**的终止响应即可将其终止;确认状态的对话的终止与确切方法相关,BYE方法终止一次会话并终止与其相关的对话。
http://blog.sina.com.cn/s/blog_4b839a1b01000bqq.html
SIP学习笔记
学习 SIP 协议最快捷的方法是通过范例来学习,
找到了一个完整的呼叫流程,let's go!
INVITE
主叫方Tesla首先发起 INVITE 消息到被叫方Marconi。INVITE 消息包含会话类型和一些呼叫所必须的参数。会话类型可能是单纯的语音,也可能是网络会议所用的多媒体视频,还可能是游戏会话。下面是消息体范例,我们来详细分析各个字段的意义。
INVITE sip:[email protected] SIP/2.0
<= 请求方法、请求地址(Request-URI)、SIP 版本号(目前都是 SIP/2.0)
<= 请求地址一般就是被叫方地址,跟 MSN 中好友 eMail 地址类似
Via: SIP/2.0/UDP lab.high-voltage.org:5060;branch=z9hG4bKfw19b
<=SIP 版本号(2.0)、传输类型(UDP)、呼叫地址、
<=branch是一随机码,它被看作传输标识
<=Via 字段中地址是消息发送方或代理转发方设备地址,一般由主机地址和端口号组成
<=传输类型可以为 UDP、TCP、TLS、SCTP
Max-Forwards: 70
<=最大跳跃数,就是经过 SIP 服务器的跳跃次数,主要是防止循环跳跃
<=每尽管一台代理服务器,该整数减一
To: G. Marconi
From: Nikola Tesla
<=如果里面有用户名标签,地址要求用尖括号包起来
<=对于 INVITE 消息,可以在 From 字段中包含 tag,它也是个随机码
Call-ID: [email protected]
<=呼叫ID是由本地设备生成的,全局唯一值。每次呼叫该值唯一不变
<=对于用户代理发送 INVITE 消息,本地将生成 From tag 和 Call-ID 全局唯一码,被叫方代理则生成 To tag 全局唯一码。这三个随机码做为整个对话中对话标识(dialog indentifier)在通话双方使用。
CSeq: 1 INVITE
<=CSeq,又叫命令队列(Command Seqence),每发送一个新的请求,该数自动加1
* 以上几个字段是所有 SIP 消息体所必须的,其它头字段有些是可选的,有些在特定请求也是必须
Subject: About That Power Outage...
Contact:
<=Contact 是 INVITE 消息所必须的,它用来路由到被叫设备地址,也称为用户代理(UA)
Content-Type: application/sdp
Content-Length: 158
<=最后两位附属字段说明消息体类型以及字段长度
v=0 <=SDP版本号,目前都是 0
o=Tesla 2890844526 2890844526 IN IP4 lab.high-voltage.org <=主叫源地址,类型等
s=Phone Call <=主题
c=IN IP4 100.101.102.103 <=连接
t=0 0 <= 时间戳
m=audio 49170 RTP/AVP 0 <=媒体
a=rtpmap:0 PCMU/8000 <=媒体属性
<=从上面 SDP 消息体我们可以得出下面信息
<=连接 IP 地址:100.101.102.103
<=媒体格式:audio
<=端口号:49170
<=媒体传输类型:RTP
<=媒体编码:PCM u Law
<=采样率:8000 Hz
180 Ringing
当被叫方接收到 INVITE 请求消息后,将回复 180 Ringing。顾名思义,就是发回铃音,提示主叫方电话已连接上了,正等待被叫应答。被叫方接收到 INVITE 消息后也会发生响铃或者其它有呼入提示,这由被叫方设定(我们可以把它想象成我们自己设定手机铃声)。对于 180 响应又被称为“消息及时响应”,它是一种用来测试被叫状态的一种响应。因此它所包含的信息不多,具体 180 响应消息如下:
SIP/2.0 180 Ringing
Via: SIP/2.0/UDP lab.high-voltage.org:5060;branch=z9hG4bKfw19b
;received=100.101.102.103 <=这里增加一个 received 参数,标识接收方 IP 地址
To: G. Marconi
From: Nikola Tesla
Call-ID: [email protected]
CSeq: 1 INVITE
Contact:
Content-Length: 0
<=注意这里 From 和 To 地址,因为它们用来指定呼叫方向,因此这里的 200 OK 响应并没有将地址对调,仍然保持原样。一点不同的是 To 头字段添加了由被叫方 Marconi 生成的 tag 标识
200 Ok
被叫响铃后,如果被叫用户 Marconi 接起电话,则发出 200 OK 响应。这个响应除了做为接通指示之外,还有一个功能是用来指定被叫允许的连接媒体格式,让主叫方确认是否可以接收该媒体。
消息体如下
SIP/2.0 200 OK
Via: SIP/2.0/UDP lab.high-voltage.org:5060;branch=z9hG4bKfw19b
;received=100.101.102.103
To: G. Marconi
From: Nikola Tesla
Call-ID:
CSeq: 1 INVITE
Contact:
Content-Type: application/sdp
Content-Length: 155
v=0
o=Marconi 2890844528 2890844528 IN IP4 tower.radio.org
s=Phone Call
c=IN IP4 200.201.202.203
t=0 0
m=audio 60000 RTP/AVP 0
a=rtpmap:0 PCMU/8000
<=从上面 SDP 消息体我们可以得出下面信息
<=终端 IP 地址:200.201.202.203
<=媒体格式:audio
<=端口号:60000
<=媒体传输类型:RTP
<=媒体编码:PCM u Law
<=采样率:8000 Hz
ACK
通话前最后一步是主叫方确认 200 OK响应。该项确认证明连接被允许,即将使用另一种协议开始媒体连接。这另一种协议是上面在SDP 消息段中所协商好的 RTP 格式。该 ACK 响应内容如下:
ACK sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP lab.high-voltage.org:5060;branch=z9hG4bK321g
Max-Forwards: 70
To: G. Marconi
From: Nikola Tesla
Call-ID:
CSeq: 1 ACK
Content-Length: 0
BYE
通话完毕后,由被叫方 Marconi 首先挂机,发送 BYE 请求命令。注意这回由 Marconi 做为主叫方了,因此 Via 字段和From、To 与 INVITE 字段有所不同。其实也就是倒置。
BYE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP tower.radio.org:5060;branch=z9hG4bK392kf
Max-Forwards: 70
To: Nikola Tesla
From: G. Marconi
Call-ID: [email protected]
CSeq: 1 BYE
Content-Length: 0
200 OK
BYE 之后,要求被叫方发 200 Ok 确认,也就是让主叫知道被叫已经知道你挂断了。(注意这里所说的主被叫角色已经倒过来了)打个比方,通话之后,有一方要求挂机,另一方需要知道它已经挂机了。
SIP/2.0 200 OK
Via: SIP/2.0/UDP tower.radio.org:5060;branch=z9hG4bK392kf
;received=200.201.202.203
To: Nikola Tesla
From: G. Marconi
Call-ID:
CSeq: 1 BYE
Content-Length: 0
到此,就是最简单的呼叫过程。该过程简单在于两个终端之间没有其它设备,完全的点对点连接,它们之间只需要知道对方 IP 地址即可。现实生活中这种呼叫形式是很少见的。
http://blog.chinaunix.net/uid-20655530-id-1589483.html
http://www.iptel.org/sip/intro/scenarios/rr/strict_vs_loose
http://blog.csdn.net/dingpeng1978/article/details/2652380
Service-Route:Service-Route在S-CSCF向UE发送REGISTER成功应答时设置,作用和Record-Route类似,用于帮助UE建立Route Set,这样UE注册后的消息(例如INVITE)通过设置Route字段无需经过I-CSCF可直接送达S-CSCF。
Path :只能用于用户向注册服务器发送的Register请求。
1如果某代理服务器希望发往用户的任何后续请求仍能经过自己,就可以在Register请求中插入一个Path字段并赋值为自身的URI。
2如果要求拓扑隐藏,经过I-CSCF的时候要把这个 I 添加到Path字段中
To 字段总是包含被呼叫方的地址(通过sip代理时是公用地址,点对点时是真实ip),要注意的是区别该标题头和sip消息请求行中的Request-URI。To在信令路径中不会被代理改变,然而Request-URI包含的是信令路径中下一跳的地址,因此在路途中被每个代理改变。
BYE sip:p3.middle.com SIP/2.0
Route:
Route:
Route:
http://www.cnblogs.com/my_life/articles/2282364.html