年参与过一个“视频通讯的App”项目,使用Sip协议通信。当时通信协议这块不是自己负责,加上时间紧、任务重等方面的原因,一直未对Sip协议进行过深入的了解。
年春天疫情突发,宅在家里终于有了空余时间。这里来详细了解一下Sip协议。
以下内容大致分为以下几个部分:
协议简介两种Sip会话模式SessionModel与PagerModel;Sip消息体结构Sip消息举例一、Sip协议简介:
SIP(SessionInitiationProtocol,会话初始协议)是由IETF(InternetEngineeringTaskForce,因特网工程任务组)制定的多媒体通信协议。广泛应用于CS(CircuitSwitched,电路交换)、NGN(NextGenerationNetwork,下一代网络)以及IMS(IPMultimediaSubsystem,IP多媒体子系统)的网络中,可以支持并应用于语音、视频、数据等多媒体业务,同时也可以应用于Presence(呈现)、InstantMessage(即时消息)等特色业务。可以说,有IP网络的地方就有SIP协议的存在。
SIP是类似于HTTP,SIP可以减少应用特别是高级应用的开发时间。由于基于IP协议的SIP利用了IP网络,固定网运营商也会逐渐认识到SIP技术对于他们的远意义。
二、Sip消息的两种会话模式
在SipIM通信应用过程中,一般存在着两种会话模式:
SessionModelPagerModel2.1、SessionModel
会话中,对于消息体内容大于字节时,一般采用SessionModel。其会话建立过程如下图所示:
主叫方A呼叫被叫方B:
步骤1:主叫方A发送INVITE请求到代理服务器;步骤2:代理服务器发送Trying响应主叫方A;步骤3~6:代理服务器搜索被叫方B的地址,获取地址后转发INVITE请求;步骤7~9:被叫方B生成的振铃响应,返回给主叫方A;步骤10~12:被叫方B生成的OK响应,返回给主叫方A;步骤13~17:主叫方A收到被叫方BOK响应后,向被叫方B发送一个ACK,会话建立;步骤18~20:会话结束后,任何参与者(A或B)都可以发送一个BYE请求来终止会话;步骤21~23:主叫方A发送OK响应来确认BYE,会话终止。注:以上的整个流程称之为一个Dialog
2.2、PagerModel
在Sip消息中,对于消息体不大于字节时,一般采用PagerModel。Sip消息通信中采用MESSAGE方法,MESSAGE方法本身并不建立Dialog,在多数应用中,每条IM消息都是独立的,颇似分页消息。
2.2.1MESSAGE方法的由来
RFC对Sip协议进行了扩展,在Sip协议中增加了MESSAGE请求方法。采用PagerModel进行通信,传递不超过字节的数据。
2.2.2MESSAGE方法消息体
当User1想给User2发送IM消息时,只需构造一个MESSAGE,发出去即可。
对于其消息体body可以是任何MIME格式。但必须支持plain/text格式,可以选择支持message/cpim(见RFC)格式,可能用message/cpim会好一点,因为已有的IM系统标准是message/cpim格式。
2.2.3PagerModel请求流程如下
以User1向User2发送MESSAGE消息为例:
步骤1:User1发送MESSAGE请求到代理服务器;步骤2:代理服务器转发User1的MESSAGE请求给USER2;步骤3:User2收到User1的消息后,回复OK给代理服务器;步骤7~9:代理服务器转发OK回复给User1
三、SIP消息体格式
SIP消息体结构与Http协议结构相似,均由三部分组成:
请求行(request-line)or状态行(status-line)消息头(header)正文(body)3.1、请求行
请求行格式:MethodRequest-URISIP-VersionCRLF
请求行举例:INVITESIP/2.0/r/n
Method以下列出了几种消息Method方法:
Request-URI
指示请求的用户或者服务的地址信息
SIP-Version请求和响应消息都需要包含SIP版本信息
3.2、状态行
状态行格式:
SIP-VersionStatus-CodeReason-PhraseCRLF
状态行举例:
SIP/2.0OK/r/n
Status-Code状态码:状态代码由3位数字组成,表示请求是否被理解或被满足。
状态代码的第一个数字定义了响应的类别,后面两位没有具体的分类。
第一个数字有五种可能的取值:
常用的状态码举例:
3.3、消息头
发送MESSAGE消息给user2
Header字段含义说明:
四、SIP消息举例
这里举两个例子:
MESSAGE消息(PagerMode)REGISTER消息4.1、MESSAGE消息(PagerModel)
以User1发送MESSAGE消息给user2为例:
步骤1:User1发送MESSAGE请求到代理服务器
步骤2:代理服务器转发User1的MESSAGE请求给USER2
代理服务器收到步骤1请求,到数据库中查找User2(注册过程中生成数据库),随后生成步骤2的数据。
步骤3:User2收到User1的消息后,回复OK给代理服务器
直接回应(-OK)没有Body,也不携带Contact头域
步骤4:代理服务器转发OK回复给User1
代理服务器收到回复后,去掉最顶端的Via,转发如下消息给User1
4.2、REGISTER消息
首先举例一个非鉴权注册消息。
4.2.1非鉴权注册消息
..2.机器发送注册消息给..2.89服务器:
当注册成功(回送OK)时,服务器发送的res消息参考如下:
4.2.2鉴权注册消息
当需要鉴权注册时
请求端..2.发送注册消息给..2.89服务器服务器对..2.发送“Unauthorized”信息给请求端,提示请求端需要带上鉴权信息重新注册请求端带上鉴权信息后(带有“Authorization”头字段)重新向服务器注册服务器验证鉴权头的正确性,如果鉴权成功,给请求端发送OK消息。若失败,继续发送消息。请求端..2.发送注册消息给..2.89服务器
服务器对..2.发送Unauthorized信息给请求端,提示请求端需要带上鉴权信息重新注册:
请求端..2.通过Authorization头字段带上鉴权头信息,发送一个新的REGISTER消息:
服务器验证鉴权头的正确性,如果鉴权成功,给请求端发送OK消息。若失败,继续发送消息
五、CPIM消息格式:
Message/CPIM是一个两部分实体,第一部分为消息元数据,第二部分为消息内容。这两部分与包装好的MIME头域相互独立,并且两部分之间用空格行隔开。消息元数据头信息遵循比MIME消息内容的头格式更严格的格式要求。
一个完整的消息格式如下:
m:Content-type:Message/CPIM
s:
h:(message-metadata-headers)
s:
e:(encapsulatedMIMEmessage-body)
其中,标签“m:”,“s:”,“h:”,“x:”并不是消息格式的一部分,而是用来区分消息的不同部分。具体含义如下:
m:整个消息的MIME消息头
s:空格分隔行
h:消息头
e:包含消息内容在内的封装好的MIME对象
x:符合MIME安全的若干消息包装
uMessage/CPIM消息的MIME消息头(m:)
消息的MIME消息头表示该消息采用的CPIM格式。具体形式为:
Content-type:Message/CPIM
u消息头(h:)
在传输过程中,消息头的格式、顺序及内容都不能被修改。
具体格式为:Key:Value
对消息头的要求有:
确保一个消息头在同一行;
每行一个消息头;
处理器不能对消息头的长度限制;
消息头的开始和结尾不能出现空格;
必须使用UTF-8字符;
使用CR,LF结束该行;
消息头名称只能包含USASCII码字符;
不能包含任何控制字符;
消息头名称冒号后必须有一个空格;
多行可以使用相同的消息头;
消息头必须配对;
在不能识别消息头的情况下,该消息头将被忽略;
消息头的顺序不能改变;
例如:
To:PoohBear
From:
DateTime:1-02-02T10:48:54-05:00
CPIM定义的消息头有:NS、Require、From、To、cc、DateTime、Sunject。
下面是一个Message/CPIM消息的例子:
m:Content-type:Message/CPIM
s:
h:From:MRSANDERS
h:To:DepressedDonkey
h:DateTime:0-12-13T13:40:00-08:00
h:Subject:theweatherwillbefinetoday
h:Subject:;lang=frbeautempsprevupouraujourdhui
h:NS:MyFeatures
h:Require:MyFeatures.VitalMessageOption
h:MyFeatures.VitalMessageOption:Confirmation-requested
h:MyFeatures.WackyMessageOption:Use-silly-font
s:
e:Content-type:text/xml;charset=utf-8
e:Content-ID
e:
e:body
e:Hereisthetextofmymessage.
e:/body
为了确保Message/CPIM的安全性,应用部署可以使用RFC,或其它合适的安全协议(如S/MIME或openPGP)对上述消息加密。
使用S/MIME和pkcs7,上述消息变为:
x:Content-Type:multipart/signed;boundary=next;micalg=sha1;protocol=application/pkcs7-signature
x:
x:--next
m:Content-Type:Message/CPIM
s:
h:From:MRSANDERS
h:To:DopeyDonkey
h:DateTime
h:Subject:theweatherwillbefinetoday
h:Subject:;lang=frbeautempsprevupouraujourdhui
h:NS:MyFeatures
h:Require:MyFeatures.VitalMessageOption
h:MyFeatures.VitalMessageOption:Confirmation-requested
h:MyFeatures.WackyMessageOption:Use-silly-font
s:
e:Content-type:text/xml;charset=utf-8
e:Content-ID:
e:
e:body
e:Hereisthetextofmymessage.
e:/body
x:--next
x:Content-Type:application/pkcs7-signature
x:
x:(signaturestuff)
:
x:--next--