会话部分:
既然已经注册了,下面就可以进行会话了。
【说明】[图1]中给出的会话流程是最基本的SIP会话流程。
另外,下面给出的是整个流程所传输的完整消息流,不过为了说明问题只是给出了跟会话流程相关的部分头域,而不是全部头域(包括实际传输中通常需要的Allow、Supported等头域,并且也没用给出路由相关的头域Route、Record-Route等,刚好RFC 3261中也有关于路由机制专门的讲解,我也会对此另外做介绍),另外,消息体的内容也省略了。因为上面我们已经结合注册流程对一些重要头域做了说明,因此,下面对头域的解释已经不是主要内容,而是对整个会话流程的把握。
Let's go!~
F1 INVITE Alice -> atlanta.com proxy
INVITE sip:
[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
Max-Forwards: 70
To: Bob <sip:
[email protected]>
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:
[email protected]>
Content-Type: application/sdp
Content-Length: 142
(Alice's SDP not shown)
我们看到,这是从Alice发给Bob的INVITE请求,也就是Alice主动向Bob发起会话请求。
消息中还包括一个Via头域,里面恰好就是Alice的URI。Alice增加这样一个头域是为了随后的响应消息能够被准确传递回来。
Alice为本次会话计算出了一个Call-ID,后面没用所在域标识符,有可能会跟其他会话混淆(别人的会话),因此不推荐这种做法。我们可以看到,本次会话后面的所有消息的Call-ID都是一样的,后面就不再说明。
Alice为本次会话选择的初始CSeq值是314159,可以看出,该值并非一定要从1开始。
Alice还在Contact头域里携带了其具体联系方式
[email protected]。我们往往在INVITE消息中通过Contact头域携带一个自己更直接的联系方式,然后被叫方也会在响应消息中通过Contact头域携带一个自己更直接的联系方式,这样,随后的消息就可以直接发往这个地址,而不是一开始的记录地址(比如
[email protected])。当某方打算改变其联系地址时,他可以通过发送一个re-INVITE消息来通知对方更新其联系地址。
【注意】Contact中联系地址的生命期可以跨越会话,在某次会话的INVITE消息中携带的Contact地址,在随后的会话或者会话外消息中一样也可以使用。
INVITE消息中携带的SDP消息体已经被省略。但是在实际使用中这是必须的部分,因为INVITE中的SDP消息体正是用于进行会话媒体协商的,没有这部分内容,SIP消息就失去了其存在的价值。
--------------------------------------------------------------------------------
F2 100 Trying atlanta.com proxy -> Alice
SIP/2.0 100 Trying
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:
[email protected]>
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Content-Length: 0
Alice的Proxy收到其INVITE消息后,立即给回了一个100响应,表示该Proxy正在尝试代为向对方发出邀请。
该Proxy还在Alice的Via头域后面添加了一个received参数,其值就是他接收到的该数据包的源地址。
该响应消息的CSeq跟上面INVITE的CSeq的值是一模一样的。
该响应消息没有消息体,因为他不需要携带其他内容。只是一个通知。
--------------------------------------------------------------------------------
F3 INVITE atlanta.com proxy -> biloxi.com proxy
INVITE sip:
[email protected] SIP/2.0
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
Max-Forwards: 69
To: Bob <sip:
[email protected]>
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:
[email protected]>
Content-Type: application/sdp
Content-Length: 142
(Alice's SDP not shown)
这是从Alice的Proxy发出的INVITE消息,对比上面的INVITE,我们可以看出他都做了哪些手脚(再次申明一下:本文不考虑Proxy的路由机制)。
手脚1:增加了一个Via头域,目的跟Alice是一样的。其实传输过程中的所有节点都会这么做,否则响应消息是无法原路返回的。
手脚2:把Max-Forwards的值减了1。
手脚3:over(其实Proxy实际做的工作远不止这些,我们所看到的只是表面现象。)
无论如何,Alice的Proxy就把这么一条做过手脚的INVITE消息发给了Bob的Proxy。
--------------------------------------------------------------------------------
F4 100 Trying biloxi.com proxy -> atlanta.com proxy
SIP/2.0 100 Trying
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:
[email protected]>
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Content-Length: 0
像上面那条100消息一样,Bob的Proxy也给Alice的Proxy回送了一个100响应。
他也在Alice的Proxy的Via头域上添加了一个received参数。
--------------------------------------------------------------------------------
F5 INVITE biloxi.com proxy -> Bob
INVITE sip:
[email protected] SIP/2.0
Via: SIP/2.0/UDP server10.biloxi.com;branch=z9hG4bK4b43c2ff8.1
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
Max-Forwards: 68
To: Bob <sip:
[email protected]>
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:
[email protected]>
Content-Type: application/sdp
Content-Length: 142
(Alice's SDP not shown)
Bob的Proxy除了像Alice的Proxy那样增加了一个Via头域,把Max-Forwards的值减1外,还做了一个非常伟大的工作——把该INVITE消息的request-URI替换成了Bob注册时的联系地址。为什么他会这么做?因为他是Bob的Proxy嘛,也就是说这个Proxy是负责biloxi.com这个域的。
【说明】在IMS中,起到这个作用的往往是被叫方的S-CSCF。
--------------------------------------------------------------------------------
F6 180 Ringing Bob -> biloxi.com proxy
SIP/2.0 180 Ringing
Via: SIP/2.0/UDP server10.biloxi.com;branch=z9hG4bK4b43c2ff8.1
;received=192.0.2.3
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:
[email protected]>;tag=a6c85cf
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
Contact: <sip:
[email protected]>
CSeq: 314159 INVITE
Content-Length: 0
经过辗转,Bob终于收到了Alice的INVITE请求。Bob的设备开始提示有会话邀请到来(可能是电话铃声响起,也可能是Bob的某个IM工具头像在闪动,如此种种),随后Bob就给返回了一个180响应,告诉Alice这边正在响铃。
有Via的保证,这个响应消息会一路返回给Alice的,除非中间某个Proxy挂掉了。
该消息中最值得一提的是Bob给To头域增加了一个tag参数,表明自己原则上接受了本次会话邀请,至于Bob是不是乐意接听就是另外一回事了。
--------------------------------------------------------------------------------
F7 180 Ringing biloxi.com proxy -> atlanta.com proxy
SIP/2.0 180 Ringing
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:
[email protected]>;tag=a6c85cf
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
Contact: <sip:
[email protected]>
CSeq: 314159 INVITE
Content-Length: 0
正如上面提到的那样,180现在就从Bob的Proxy发给了Alice的Proxy。
--------------------------------------------------------------------------------
F8 180 Ringing atlanta.com proxy -> Alice
SIP/2.0 180 Ringing
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:
[email protected]>;tag=a6c85cf
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
Contact: <sip:
[email protected]>
CSeq: 314159 INVITE
Content-Length: 0
Alice的Proxy又传给了Alice。
--------------------------------------------------------------------------------
F9 200 OK Bob -> biloxi.com proxy
SIP/2.0 200 OK
Via: SIP/2.0/UDP server10.biloxi.com;branch=z9hG4bK4b43c2ff8.1
;received=192.0.2.3
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:
[email protected]>;tag=a6c85cf
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:
[email protected]>
Content-Type: application/sdp
Content-Length: 131
(Bob's SDP not shown)
Bob看到有Alice的主动邀请,心中窃喜啊,于是立即提起话筒,与此同时,Bob的SIP终端就向Alice发出了一个200 INVITE消息,表明Bob同意了本次通话。
该响应消息所走路径跟上面的180完全一样。
值得一提的是,这个200响应的消息体就不再是空了,因为Bob要给Alice回传他的媒体信息(使用什么方式通信,通信服务器地址又如何等)。
--------------------------------------------------------------------------------
F10 200 OK biloxi.com proxy -> atlanta.com proxy
SIP/2.0 200 OK
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:
[email protected]>;tag=a6c85cf
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:
[email protected]>
Content-Type: application/sdp
Content-Length: 131
(Bob's SDP not shown)
我传。。
--------------------------------------------------------------------------------
F11 200 OK atlanta.com proxy -> Alice
SIP/2.0 200 OK
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:
[email protected]>;tag=a6c85cf
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:
[email protected]>
Content-Type: application/sdp
Content-Length: 131
(Bob's SDP not shown)
我再传。。
200 INVITE响应消息就传给了Alice。
--------------------------------------------------------------------------------
F12 ACK Alice -> Bob
ACK sip:
[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds9
Max-Forwards: 70
To: Bob <sip:
[email protected]>;tag=a6c85cf
From: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 ACK
Content-Length: 0
Alice收到Bob的200响应后,就给回了一个ACK消息,以表明她收到了Bob的200响应。同时表明会话可以正式开始了。接下来就是媒体层面的事情了(比如RTP/MSRP等)。
另外,因为ACK所确认的是2xx响应,因此,其CSeq中的序列号跟上面的仍然是一样的。
--------------------------------------------------------------------------------
Alice与Bob通话中。。
--------------------------------------------------------------------------------
F13 BYE Bob -> Alice
好,现在他们二人通话结束,Bob先挂了电话。于是他向Alice发出了一个BYE请求。
该请求的request-URI也是Alice的Contact地址。
相比上面的消息流,这个BYE已经是另外一个事务(上面的消息看似不少,但都是INVITE引发的,属于同一个事务),因此其CSeq中的序列号以及Via中的branch参数值已经跟上面的不一样了。但是由于属于同一个会话,因此Call-ID以及各自的tag还都是一样的。只是此处的From已经是Bob了。
【注意】Bob所发出的Cseq序列号跟Alice的是独立的。
--------------------------------------------------------------------------------
F14 200 OK Alice -> Bob
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.0.2.4;branch=z9hG4bKnashds10
From: Bob <sip:
[email protected]>;tag=a6c85cf
To: Alice <sip:
[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 231 BYE
Content-Length: 0
Alice收到Bob的BYE请求后发回一个200确认响应,表明Alice同时也结束了本次会话。
这里我有两个疑问:
1,如果双方几乎同时挂电话,将会如何?
2,如果Alice不给200响应,将会如何?
需要再研读一下RFC3261。