在P2P通讯标准协议(二)中,介绍了TURN的基本交互流程,在上篇结束部分也有说到,TURN做为STUN
协议的一个拓展,保持了STUN的工具性质,而不做为完整的NAT传输解决方案,只提供穿透NAT的功能,
而且由具体的应用程序来使用.虽然TURN也能够独立工做,但其自己就是被设计为ICE/RFC5245
的一部分,本章就来介绍一下ICE协议的具体内容.git
ICE信息的描述格式一般采用标准的SDP,其全称为Session Description Protocol,即会话描述协议.
SDP只是一种信息格式的描述标准,不属于传输协议,可是能够被其余传输协议用来交换必要的信息,如SIP和RTSP等.github
一个SDP会话描述包含以下部分:编程
由于在中途参与会话也许会受限制,因此可能会须要一些额外的信息:服务器
通常来讲,SDP必须包含充分的信息使得应用程序可以加入会话,而且能够提供任何非参与者使用时须要知道的资源
情况,后者在当SDP同时用于多个会话声明协议时尤为有用.网络
SDP是基于文本的协议,使用ISO 10646字符集和UTF-8编码.SDP字段名称和属性名称只使用UTF-8的一个子集US-ASCII,
所以不能存在中文.虽然理论上文本字段和属性字段支持全集,但最好仍是不要在其中使用中文.session
SDP会话描述包含了多行以下类型的文本:app
<type>=<value>
其中type是大小写敏感的,其中一些行是必需要有的,有些是可选的,全部元素都必须以固定顺序给出.固定的顺序极大改善了
错误检测,同时使得处理端设计更加简单.以下所示,其中可选的元素标记为* :分布式
会话描述: v= (protocol version) o= (originator and session identifier) s= (session name) i=* (session information) u=* (URI of description) e=* (email address) p=* (phone number) c=* (connection information -- not required if included in all media) b=* (zero or more bandwidth information lines) One or more time descriptions ("t=" and "r=" lines; see below) z=* (time zone adjustments) k=* (encryption key) a=* (zero or more session attribute lines) Zero or more media descriptions 时间信息描述: t= (time the session is active) r=* (zero or more repeat times) 多媒体信息描述(若是有的话): m= (media name and transport address) i=* (media title) c=* (connection information -- optional if included at session level) b=* (zero or more bandwidth information lines) k=* (encryption key) a=* (zero or more media attribute lines)
全部元素的type都为小写,而且不提供拓展.可是咱们能够用a(attribute)字段来提供额外的信息.一个SDP描述的例子以下:ide
v=0 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5 s=SDP Seminar i=A Seminar on the session description protocol u=http://www.example.com/seminars/sdp.pdf e=j.doe@example.com (Jane Doe) c=IN IP4 224.2.17.12/127 t=2873397496 2873404696 a=recvonly m=audio 49170 RTP/AVP 0 m=video 51372 RTP/AVP 99 a=rtpmap:99 h263-1998/90000
具体字段的type/value描述和格式能够去参考RFC4566.工具
上文说到,SDP用来描述多播主干网络的会话信息,可是并无具体的交互操做细节是如何实现的,所以RFC3264
定义了一种基于SDP的offer/answer模型.在该模型中,会话参与者的其中一方生成一个SDP报文构成offer,
其中包含了一组offerer但愿使用的多媒体流和编解码方法,以及offerer用来接收改数据的IP地址和端口信息.
offer传输到会话的另外一端(称为answerer),由answerer生成一个answer,即用来响应对应offer的SDP报文.
answer中包含不一样offer对应的多媒体流,并指明该流是否能够接受.
RFC3264只介绍了交换数据过程,而没有定义传递offer/answer报文的方法,后者在RFC3261/SIP
即会话初始化协议中描述.值得一提的是,offer/answer模型也常常被SIP做为一种基本方法使用.
offer/answer模型在SDP报文的基础上进行了一些定义,工做过程不在此描述,须要了解细节的朋友能够参考RFC3261.
ICE的全称为Interactive Connectivity Establishment,即交互式链接创建.初学者可能会将其与网络编程的ICE
弄混,其实那是不同的东西,在网络编程中,如C++的ICE库,都是指Internate Communications Engine,
是一种用于分布式程序设计的网络通讯中间件.咱们这里说的只是交互式链接创建.
ICE是一个用于在offer/answer模式下的NAT传输协议,主要用于UDP下多媒体会话的创建,其使用了STUN协议以及TURN
协议,同时也能被其余实现了offer/answer模型的的其余程序所使用,好比SIP(Session Initiation Protocol).
使用offer/answer模型(RFC3264)的协议一般很难在NAT之间穿透,由于其目的通常是创建多媒体数据流,并且在报文中还
携带了数据的源IP和端口信息,这在经过NAT时是有问题的.RFC3264还尝试在客户端之间创建直接的通路,所以中间就缺乏
了应用层的封装.这样设计是为了减小媒体数据延迟,减小丢包率以及减小程序部署的负担.然而这一切都很难经过NAT而完成.
有不少解决方案可使得这些协议运行于NAT环境之中,包括应用层网关(ALGs)
,Classic STUN
以及Realm Specific IP
+SDP
协同工做等方法.不幸的是,这些技术都是在某些网络拓扑下工做很好,而在另外一些环境下表现又不好,所以咱们须要一个单一的,
可自由定制的解决方案,以便能在全部环境中都能较好工做.
一个典型的ICE工做环境以下,有两个端点L和R,都运行在各自的NAT以后(他们本身也许并不知道),NAT的类型和性质也是未知的.
L和R经过交换SDP信息在彼此之间创建多媒体会话,一般交换经过一个SIP服务器完成:
+-----------+ | SIP | +-------+ | Srvr | +-------+ | STUN | | | | STUN | | Srvr | +-----------+ | Srvr | | | / \ | | +-------+ / \ +-------+ /<- Signaling ->\ / \ +--------+ +--------+ | NAT | | NAT | +--------+ +--------+ / \ / \ / \ +-------+ +-------+ | Agent | | Agent | | L | | R | | | | | +-------+ +-------+
ICE的基本思路是,每一个终端都有一系列传输地址
(包括传输协议,IP地址和端口)的候选,能够用来和其余端点进行通讯.
其中可能包括:
虽然潜在要求任意一个L的候选地址都能用来和R的候选地址进行通讯.可是实际中发现有许多组合是没法工做的.举例来讲,
若是L和R都在NAT以后并且不处于同一内网,他们的直接地址就没法进行通讯.ICE的目的就是为了发现哪一对候选地址的
组合能够工做,而且经过系统的方法对全部组合进行测试(用一种精心挑选的顺序).
为了执行ICE,客户端必需要识别出其全部的地址候选,ICE中定义了三种候选类型,有些是从物理地址或者逻辑网络接口继承
而来,其余则是从STUN或者TURN服务器发现的.很天然,一个可用的地址为和本地网络接口直接联系的地址,一般是内网地址,
称为HOST CANDIDATE
,若是客户端有多个网络接口,好比既链接了WiFi又插着网线,那么就可能有多个内网地址候选.
其次,客户端经过STUN或者TURN来得到更多的候选传输地址,即SERVER REFLEXIVE CANDIDATES
和RELAYED CANDIDATES
,
若是TURN服务器是标准化的,那么两种地址均可以经过TURN服务器得到.当L得到全部的本身的候选地址以后,会将其
按优先级排序,而后经过signaling通道发送到R.候选地址被存储在SDP offer报文的属性部分.当R接收到offer以后,
就会进行一样的获选地址收集过程,并返回给L.
这一步骤以后,两个对等端都拥有了若干本身和对方的候选地址,并将其配对,组成CANDIDATE PAIRS
.为了查看哪对组合
能够工做,每一个终端都进行一系列的检查.每一个检查都是一次STUN request/response传输,将request从候选地址对的本地
地址发送到远端地址. 链接性检查的基本原则很简单:
两端链接性测试,结果是一个4次握手过程:
L R - - STUN request -> \ L's <- STUN response / check <- STUN request \ R's STUN response -> / check
值的一提的是,STUN request的发送和接收地址都是接下来进多媒体传输(如RTP和RTCP)的地址和端口,因此,
客户端其实是将STUN协议与RTP/RTCP协议在数据包中进行复用(而不是在端口上复用).
因为STUN Binding request用来进行链接性测试,所以STUN Binding response中会包含终端的实际地址,
若是这个地址和以前学习的全部地址都不匹配,发送方就会生成一个新的candidate,称为PEER REFLEXIVE CANDIDATE
,
和其余candidate同样,也要经过ICE的检查测试.
全部的ICE实现都要求与STUN(RFC5389)兼容,而且废弃Classic STUN(RFC3489).ICE的完整实现既生成checks(做为STUN client),
也接收checks(做为STUN server),而lite实现则只负责接收checks.这里只介绍完整实现状况下的检查过程.
1. 为中继候选地址生成许可(Permissions).
2. 从本地候选往远端候选发送Binding Request.
在Binding请求中一般须要包含一些特殊的属性,以在ICE进行链接性检查的时候提供必要信息.
3. 处理Response.
当收到Binding Response时,终端会将其与Binding Request相联系,一般经过事务ID.随后将会将此事务ID与
候选地址对进行绑定.
Waiting
.终端收到成功响应以后,先检查其mapped address是否与本地记录的地址对有匹配,若是没有则生成一个新的候选地址.
即对等端的反射地址.若是有匹配,则终端会构造一个可用候选地址对(valid pair).一般极可能地址对不存在于任何
检查列表中,检索检查列表中没有被服务器反射的本地地址,这些地址把它们的本地候选转换成服务器反射地址的基地址,
并把冗余的地址去除掉.
本文介绍了一种完整的NAT环境通讯解决方案ICE,而且对其中涉及到的概念SDP和offer/answer模型也做了简要介绍.
ICE是使用STUN/TURN工具性质的最主要协议之一,其中TURN一开始也被设计为ICE协议的一部分.值的一提的是,
本文只是对这几种协议做了概述性的说明,而具体工做过程和详细的属性描述都未包含,所以若是须要根据协议来
实现具体的应用程序,还须要对RFC的文档进行仔细阅读.这里给出一些参考:
而具体的代码以及实现能够参考: