SIP(Session Initiation Protocol,会话初始协议)是一个控制发起、修改和终结交互式多媒体(音视频、聊天、游戏等)会话的信令协议(RFC 3261)。SIP是一个基于文本的协议,已为即时消息、列席和事件通知等定义了扩展。
为建立会话,SIP一般需要使用以下协议:
- DNS:解析主机或域名;
- SDP(会话描述协议):描述、协商多媒体会话参数;
- RTP(实时传输协议): 传输实时数据(音视频媒体包)到端点;
- RSVP(资源预留协议):在建立媒体会话前预留出所需的带宽;
- TLS(安全传输层协议):可基于此提供SIP的隐私性和完整性;
- STUN(NAT的UDP简单穿透):发现是否有地址转换;
部分术语简介
- Address-of-Record(AOR):是一个SIP或SIPS URI,它指向带位置服务的一个域,位置服务可以将一个URI与另一个URI(可能找到用户的URI)映射。典型的,通过注册来填写位置服务。通常认为AOR是用户的“公开地址”。
- Back-to-Back User Agent(B2BUA):背对背用户代理,是一个逻辑实体,它接收请求,并作为用户代理服务器(UAS)处理该请求。为确定如何应答一个请求,它作为用户代理客户端(UAC)并生成请求。与代理服务器不同,B2BUA保持对话状态,并参与其建立的对话中发送的所有请求。由于B2BUA是UAC和UAS间的连接,所以不需要明确定义其行为。
- User Agent Client(UAC):用户代理客户端是创建新请求,然后使用客户端事务状态机发送请求的逻辑实体。UAC角色仅存在事务的持续时间内。换言之,如果软件发起一个请求,它仅在该事务的持续时间内是一个UAC。如果随后它接收到一个请求,在处理此事务时,它被假想成一个用户代理服务器角色。
- User Agent Server(UAS):用户代理服务器是一个逻辑实体,它产生SIP请求的响应。响应接收、拒绝和重定向请求。该角色仅存在于事务期间。换言之,如果软件对请求作出响应,那么它在事务期间就是UAS。如果随后它产生一个请求,那么在处理事务的期间我们就把它假想成用户代理客户端。
- User Agent(UA):既能作为用户代理客户端又能作为用户代理服务器的逻辑实体。角色UAC和UAS,以及代理和重定向服务器都是定义在事务的基础上的。例如,当用户发起一个呼叫发送初始INVITE请求时,它作为UAC;当它从被呼叫者接收BYE请求时,作为UAS。类似的,同一软件能作为一个请求的代理服务器和下一个请求的重定向服务器。以上定义的代理、位置和注册服务器都是逻辑实体。实现时可能将它们结合到一个应用中。
SIP消息基础
SIP消息可分为SIP请求和响应,由为SIP网络实体传送信令和路由信息的标题头字段(RFC3261)组成。
SIP寻址
SIP地址在网络中用于识别一个用户或资源,常被称为SIP URI,有类似EMail的地址格式:
sip:[email protected]:port
port是可选的,若没有则使用默认5060
SIP请求:
是客户端发给服务器激活一个SIP操作的消息,由一个方法名(Method)、一个请求URI(Request-URI)和一个协议版本 (SIP-Version)组成,三个部分之间以空格(SP)间隔。
Request-Line = Method + SP + Request-URI + SP + SIP-Version + CRLF
RFC中定义了6中请求:
- INVITE:表明接收用户或服务被邀请加入一个会话;也可以使用这种方式来修改先前建立会话的特性;成功响应(200 OK)表明被叫方愿意参与会话;
- ACK:确认UAC已经接收到了INVITE请求的最终响应(只与INVITE请求一起使用);用于结束一个200 OK响应;若INVITE请求中不含有会话描述信息,ACK可以包含一个最终会话描述的消息体;
- OPTION:UA用此向UAS查询它的功能;
- BYE:用于终结一个先前建立的会话;
- CANCEL:使UAC和网络服务器取消一个正在进行的请求(如INVITE);
- REGISTER:客户端注册其目前的位置信息;
SIP响应:
服务器向客户端发送SIP响应,指明客户端先前发送给服务器的SIP请求的状态;由一个协议版本(SIP-Version),一个状态码(Status-Code)和一个原因说明(Reason-Phrase)组成,类似于请求消息,三个部分之间也以空格字符(SP)间隔。
Status-Line := SIP-Version + SP + Status-Code + SP + Reason-Phrase + CRLF
状态码是一个100~699之间的3位正整数(具体参见后面附录),它表示对于一个请求消息的响应结果;原因说明是一串可以显示的字符,用于对响应的状态码进行简短说明。
- 1xx:临时响应 (Provisional);之前的请求消息已经收到,并准备接着处理后面的请求消息。
- 2xx:成功响应 (Success); 操作成功,请求消息已被收到并且成功地处理。
- 3xx:重定向响应 (Redirection); 服务器向客户端返回其它可能的位置,客户端应当根据响应中包含的地址信息向另一个服务器重发请求消息。
- 4xx: 客户端错误 (Client Error); 请求由于客户端的错误而失败,客户端可以根据响应状态码修改并重发刚才的请求消息。
- 5xx:服务器错误 (Server Error) ;请求由于服务器的错误而失败,客户端可以向另一个服务器重发请求消息。
- 6xx:全局错误(Global Failure); 请求失败,客户端不应该再向任何服务器重发该请求消息。
SIP标题头
遵从HTTP标题头(RFC2616)定义的同样格式:每个标题头由字段名,紧跟着冒号(:)和字段组成。
主要标题头(详情参见SIP常见头域(header)说明):
- From:定义请求发起者(通常是发送者AOR),包含SIP或SIP URI和一个可选的显示名字;
- To:定义了请求的接收者(通常是接收者AOR),包含SIP或SIP URI和一个可选的显示名字;因重定向和转移,SIP请求不一定发送给‘希望的’接收者;
- Call-ID:定义了一系列的SIP消息,对所有由对话中的UA发送的所有SIP请求和响应,Call-ID必须唯一;
- Cseq:由一个整数值和一个方式名称组成,在一个对话中标识和序列SIP请求,也区分重传和新消息;
- Via:定义请求路径和响应要发送的地址;
- Contact:定义US希望接收新SIP请求的SIP或SIPS URI(实际地址);
- Allow:列出产生SIP消息的UA所支持的功能集合;
- Supported:列出所有UA支持的SIP扩展(RFC3262);
- Require:包含远端UA必须支持的SIP扩展;
- Content-Type:请求或响应的消息体类型;
- Content-Length:请求或响应的消息体的大小(十进制);
事务与会话
Transaction事务
是指一个请求消息以及这个请求对应的所有响应消息的集合;对于INVITE事务来讲,除包含INVITE请求和对应的响应消息外,在非成功响应的情况下,还包括ACK请求。Via头中的branch参数能够唯一确定一个事务。branch值相同,代表同一个 transaction(事务)。事务是由事件(方法)来引起的,一个方法(Method)的建立和到来都将建立新的事务。(实际上当收到新消息时,就是根据branch来查找对应的事务)
根据sip协议描述,一个transaction由5个必要部分组成:from、to、Via头中的branch参数、call-id和cseq,这5个部分一起识别某一个transaction,如果缺少任何一部分,该transaction就会设置失败。
Dialog对话
是两个UA之间持续一段时间的点对点的SIP连接,它使UA之间的消息变得有序,同时给出请求消息的正确的路由。即Call-ID、from-tag以及to-tag三个值的组合能够唯一标识一次对话。对话一般是由Invite and Subscribe 来创建的。即对话处于确定阶段时,对话已经建立起来。
Session会话
是一次通信过程中所有参与者之间的关联关系以及他们之间的媒体流的集合。只有当媒体协商成功后,会话才能被建立起来。
三者区别联系
- 对话是end-point对end-point的关系,即真实的通信双方,而transaction 是hop by hop的关系,即路由过程中交互的双方。
- Transaction:维护hop to hop状态,包括一个请求和其触发的所有响应,包括若干暂时响应和一个最终响应。生命周期从请求产生到收到最终响应。
- Dialog:维护peer to peer状态,目前只有invite和subscribe请求会触发dialog。其生命周期贯穿一个端到端会话的始终。
下面的示意图清晰的显示了它们之间的关系(RINGING 是 1xx 响应, OK是 2xx 响应) :
- caller呼叫callee的号码来建立一系列的对话(Dialogs):
- UA-A与B2BUA之间的对话;
- B2BUA与UA-B之间的对话;
- 这些对话组成了一个呼叫(Call),即一个会话。

SIP扩展协商机制
SIP要求SIP实体忽略接收到的SIP消息中不知道的标题头,SIP扩展(如RFC3841)可以在现有的方式下定义新的标题头字段,SIP扩展需定义选项标记(tag):
- Require标题头:UAC坚持UAS必须理解处理请求的扩展,若UAS不支持必须通过Unsupported标题头包含不支持的选项标签来拒绝请求;UAC看重新发送不含扩展的请求或终止事务;(如SIP扩展:100rel)
- Supported标题头:告诉UAS,UAC支持一定的扩展,由UAS决定在响应消息中它是否需要使用这些扩展;(如SIP Session Timer)
- Allow标题头:列出产生SIP消息的UA所支持的功能集合;
SDP会话描述协议
SIP使用SDP(RFC4566)进行媒体会话实际参数的描述,包括:媒体类型、编码、比特率(bit rate)、以及会话相关的地址与端口号。
SDP包括以下一些方面:
- 会话的名称和目的
- 会话存活时间
- 包含在会话中的媒体信息,包括:
- 媒体类型(video,audio, etc)
- 传输协议(RTP/UDP/IP,H.320, etc)
- 媒体格式(H.261video, MPEG video, etc)
- 多播或远端(单播)地址和端口
- 为接收媒体而需的信息(addresses, ports, formats and so on)
- 使用的带宽信息
- 可信赖的接洽信息(Contact information)
SDP会话描述由多行<type>=<value>组成。其中<type>是一个字符。<value>是一个字符串,其格式视<type>而定。整个协议区分大小写。“=”两侧不允许有空格。
v= (protocol version)
o= (owner/creator and session identifier).
s= (session name)
i=* (session information)
u=* (URI of description)
e=* (email address)
p=* (phone number)
c=* (connection information)
b=* (bandwidth information)
One or more time descriptions (seebelow)
z=* (time zone adjustments)
k=* (encryption key)
a=* (zero or more session attributelines)
Zero or more media descriptions (seebelow)
Times
t=<start time> <stop time>
描述了会话的开始时间和结束时间。
<start time> 和<stop time> 为NTP时间,单位是秒。假如<stop time>为零表示过了<start time>时间后会话一直持续。当<start time> 和<stoptime>均为零时表示持久会话。建议start time和stoptime不要设为0。因为不知道此会话的开始和结束时间,增加了调度(scheduling)的难度。
SDP Field
Media Type
媒体级会话VLC播放g711音频的sdp文件示例:
m=audio 8888 RTP/AVP 0
a=rtpmap:0 pcma/8000/1
a=framerate:25 #8000/25=320Byte,每个rtp包的音频数据为320byte,时间戳增值为320
c=IN IP4 192.168.1.230
附录:消息应答
类型 | 状态码 | 状态说明 |
临时应答 (1XX) | 100 Trying | 正在处理中 |
180 Ringing | 振铃 | |
181 Call being forwarder | 呼叫被转发 | |
182 Queue | 排队 | |
183 Session progress | 会话进行 | |
会话成功 (2XX) | 200 OK | 会话成功 |
重定向 (3XX) | 300 Multiple | 多重选择 |
301 Moved permanently | 永久移动 | |
302 Moved temporaily | 临时移动 | |
305 Use proxy | 用户代理 | |
380 Alternative service | 替代服务 | |
请求失败 (4XX) | 400 Bad request | 错误请求 |
401 Unauthorized | 未授权 | |
402 Payment required | 付费要求 | |
403 Forbidden | 禁止 | |
404 Not found | 未发现 | |
405 Method no allowed | 方法不允许 | |
406 Not acceptable | 不可接受 | |
407 Provy authentication required | 代理需要认证 | |
408 Request timeout | 请求超时 | |
410 Gone | 离开 | |
413 Request entity too large | 请求实体太大 | |
414 Request-url too long | 请求URL太长 | |
415 Unsupported media type | 不支持的媒体类型 | |
416 Unsupported url scheme | 不支持的URL计划 | |
420 Bad extension | 不良扩展 | |
421 Extension required | 需要扩展 | |
423 interval too brief | 间隔太短 | |
480 Temporarily unavailable | 临时失效 | |
481 call/Transaction does not exist | 呼叫/事务不存在 | |
482 loop detected | 发现环路 | |
483 too many hops | 跳数太多 | |
484 address incomplete | 地址不完整 | |
485 ambiguous | 不明朗 | |
486 busy here | 这里忙 | |
487 request terminated | 请求终止 | |
488 not acceptable here | 这里请求不可接受 | |
491 request pending | 未决请求 | |
493 undecipherable | 不可辨识 | |
服务器失败 (5XX) | 500 server internal error | 服务器内部错误 |
501 not implemented | 不可执行 | |
502 bad gateway | 坏网关 | |
503 service unavailable | 服务无效 | |
504 server time-out | 服务器超时 | |
505 version not supported | 版本不支持 | |
513 message too large | 消息太大 | |
全局性错误(6XX) | 600 busy everywhere | 全忙 |
603 decline | 丢弃 | |
604 does not exist anywhere | 不存在 | |
606 not acceptable | 不可接受 |