在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的文檔進行仔細閱讀.這裏給出一些參考:
而具體的代碼以及實現能夠參考: