P2P通訊標準協議(三)之ICE

P2P通訊標準協議(二)中,介紹了TURN的基本交互流程,在上篇結束部分也有說到,TURN做爲STUN
協議的一個拓展,保持了STUN的工具性質,而不做爲完整的NAT傳輸解決方案,只提供穿透NAT的功能,
而且由具體的應用程序來使用.雖然TURN也能夠獨立工做,但其自己就是被設計爲ICE/RFC5245
的一部分,本章就來介紹一下ICE協議的具體內容.git


SDP

ICE信息的描述格式一般採用標準的SDP,其全稱爲Session Description Protocol,即會話描述協議.
SDP只是一種信息格式的描述標準,不屬於傳輸協議,可是能夠被其餘傳輸協議用來交換必要的信息,如SIP和RTSP等.github

SDP信息

一個SDP會話描述包含以下部分:編程

  • 會話名稱和會話目的
  • 會話的激活時間
  • 構成會話的媒體(media)
  • 爲了接收該媒體所須要的信息(如地址,端口,格式等)

由於在中途參與會話也許會受限制,因此可能會須要一些額外的信息:服務器

  • 會話使用的的帶寬信息
  • 會話擁有者的聯繫信息

通常來講,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.工具

Offer/Answer模型

上文說到,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

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工做流程

一個典型的ICE工做環境以下,有兩個端點L和R,都運行在各自的NAT以後(他們本身也許並不知道),NAT的類型和性質也是未知的.
L和R經過交換SDP信息在彼此之間創建多媒體會話,一般交換經過一個SIP服務器完成:

+-----------+
                 |    SIP    |
+-------+        |    Srvr   |         +-------+
| STUN  |        |           |         | STUN  |
| Srvr  |        +-----------+         | Srvr  |
|       |        /           \         |       |
+-------+       /             \        +-------+
               /<- Signaling ->\
              /                 \
         +--------+          +--------+
         |  NAT   |          |  NAT   |
         +--------+          +--------+
           /                       \
          /                         \
         /                           \
     +-------+                    +-------+
     | Agent |                    | Agent |
     |   L   |                    |   R   |
     |       |                    |       |
     +-------+                    +-------+

ICE的基本思路是,每一個終端都有一系列傳輸地址(包括傳輸協議,IP地址和端口)的候選,能夠用來和其餘端點進行通訊.
其中可能包括:

  • 直接和網絡接口聯繫的傳輸地址(host address)
  • 通過NAT轉換的傳輸地址,即反射地址(server reflective address)
  • TURN服務器分配的中繼地址(relay address)

雖然潛在要求任意一個L的候選地址都能用來和R的候選地址進行通訊.可是實際中發現有許多組合是沒法工做的.舉例來講,
若是L和R都在NAT以後並且不處於同一內網,他們的直接地址就沒法進行通訊.ICE的目的就是爲了發現哪一對候選地址的
組合能夠工做,而且經過系統的方法對全部組合進行測試(用一種精心挑選的順序).

爲了執行ICE,客戶端必需要識別出其全部的地址候選,ICE中定義了三種候選類型,有些是從物理地址或者邏輯網絡接口繼承
而來,其餘則是從STUN或者TURN服務器發現的.很天然,一個可用的地址爲和本地網絡接口直接聯繫的地址,一般是內網地址,
稱爲HOST CANDIDATE,若是客戶端有多個網絡接口,好比既鏈接了WiFi又插着網線,那麼就可能有多個內網地址候選.

其次,客戶端經過STUN或者TURN來得到更多的候選傳輸地址,即SERVER REFLEXIVE CANDIDATESRELAYED CANDIDATES,
若是TURN服務器是標準化的,那麼兩種地址均可以經過TURN服務器得到.當L得到全部的本身的候選地址以後,會將其
按優先級排序,而後經過signaling通道發送到R.候選地址被存儲在SDP offer報文的屬性部分.當R接收到offer以後,
就會進行一樣的獲選地址收集過程,並返回給L.

這一步驟以後,兩個對等端都擁有了若干本身和對方的候選地址,並將其配對,組成CANDIDATE PAIRS.爲了查看哪對組合
能夠工做,每一個終端都進行一系列的檢查.每一個檢查都是一次STUN request/response傳輸,將request從候選地址對的本地
地址發送到遠端地址. 鏈接性檢查的基本原則很簡單:

  1. 以必定的優先級將候選地址對進行排序.
  2. 以該優先級順序發送checks請求
  3. 從其餘終端接收到checks的確認信息

兩端鏈接性測試,結果是一個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的檢查測試.

鏈接性檢查(Connectivity Checks)

全部的ICE實現都要求與STUN(RFC5389)兼容,而且廢棄Classic STUN(RFC3489).ICE的完整實現既生成checks(做爲STUN client),
也接收checks(做爲STUN server),而lite實現則只負責接收checks.這裏只介紹完整實現狀況下的檢查過程.

1. 爲中繼候選地址生成許可(Permissions).

2. 從本地候選往遠端候選發送Binding Request.

在Binding請求中一般須要包含一些特殊的屬性,以在ICE進行鏈接性檢查的時候提供必要信息.

  • PRIORITY 和 USE-CANDIDATE
    • 終端必須在其request中包含PRIORITY屬性,指明其優先級,優先級由公式計算而得.
      若是有須要也能夠給出特別指定的候選(即USE-CANDIDATE屬性).
  • ICE-CONTROLLED和ICE-CONTROLLING
    • 在每次會話中,每一個終端都有一個身份,有兩種身份,即受控方(controlled role)和主控方(controlling role).
      主控方負責選擇最終用來通信的候選地址對,受控方被告知哪一個候選地址對用來進行哪次媒體流傳輸,
      而且不生成更新過的offer來提示這次告知.發起ICE處理進程(即生成offer)的一方必須是主控方,而另外一方則是受控方.
      若是終端是受控方,那麼在request中就必須加上ICE-CONTROLLED屬性,一樣,若是終端是主控方,就須要ICE-CONTROLLING屬性.
  • 生成Credential
    • 做爲鏈接性檢查的Binding Request必須使用STUN的短時間身份驗證.驗證的用戶名被格式化爲一系列username段
      的聯結,包含了發送請求的全部對等端的用戶名,以冒號隔開;密碼就是對等端的密碼.

3. 處理Response.

當收到Binding Response時,終端會將其與Binding Request相聯繫,一般經過事務ID.隨後將會將此事務ID與
候選地址對進行綁定.

  • 失敗響應
    • 若是STUN傳輸返回487(Role Conflict)錯誤響應,終端首先會檢查其是否包含了ICE-CONTROLLED或ICE-CONTROLLING
      屬性.若是有ICE-CONTROLLED,終端必須切換爲controlling role;若是請求包含ICE-CONTROLLING屬性,
      則必須切換爲controlled role.切換好以後,終端必須使產生487錯誤的候選地址對進入檢查隊列中,
      並將此地址對的狀態設置爲Waiting.
  • 成功響應,一次鏈接檢查在知足下列全部狀況時候就被認爲成功:
    • STUN傳輸產生一個Success Response
    • response的源IP和端口等於Binding Request的目的IP和端口
    • response的目的IP和端口等於Binding Request的源IP和端口

終端收到成功響應以後,先檢查其mapped address是否與本地記錄的地址對有匹配,若是沒有則生成一個新的候選地址.
即對等端的反射地址.若是有匹配,則終端會構造一個可用候選地址對(valid pair).一般極可能地址對不存在於任何
檢查列表中,檢索檢查列表中沒有被服務器反射的本地地址,這些地址把它們的本地候選轉換成服務器反射地址的基地址,
並把冗餘的地址去除掉.

後記

本文介紹了一種完整的NAT環境通訊解決方案ICE,而且對其中涉及到的概念SDP和offer/answer模型也做了簡要介紹.
ICE是使用STUN/TURN工具性質的最主要協議之一,其中TURN一開始也被設計爲ICE協議的一部分.值的一提的是,
本文只是對這幾種協議做了概述性的說明,而具體工做過程和詳細的屬性描述都未包含,所以若是須要根據協議來
實現具體的應用程序,還須要對RFC的文檔進行仔細閱讀.這裏給出一些參考:

而具體的代碼以及實現能夠參考:

相關文章
相關標籤/搜索