WebRTC 及點對點網路通訊機制

tristan發表於2019-03-01

原文請查閱這裡,略有刪減,本文采用知識共享署名 4.0 國際許可協議共享,BY Troland

這是 JavaScript 工作原理第十八章。

概述

何為 WebRTC ?首先,字面上已經給出了關於這一技術的大量資訊,RTC 即為實時通訊技術。

WebRTC 填補了網頁開發平臺中的一個重要空白。在以往,只有諸如桌面聊天程式這樣的 P2P 技術才能夠實現實時通訊而網頁不行。但是 WebRTC 的出現改變了這一狀況。

WebRTC 本質上允許網頁程式建立點對點通訊,我們將會在隨後的章節中進行介紹。我們將討論如下主題,以便向開發者全面介紹 WebRTC 的內部構造:

  • 點對點通訊
  • 防火牆和 NAT 穿透
  • 信令,會話及協議
  • WebRTC 介面

點對點通訊

每個使用者的網頁瀏覽器必須按照如下步驟以實現通過網頁瀏覽器進行的點對點通訊:

  • 同意開始進行通訊
  • 知道如何定位另一個點
  • 繞過安全和防火牆限制
  • 實時傳輸所有多媒體通訊資訊

眾所周知,基於瀏覽器的點對點通訊的最大挑戰之一即如何定位和建立與另一個網頁瀏覽器進行通訊的網路套接字以進行雙向資料傳輸。我們將會克服建立與此種網路連線相關的困難。

每當網頁程式需要資料或者靜態資源,會直接從相應的伺服器獲取,僅此而已。但是,如果若想要通過直接連線使用者的瀏覽器來建立點對點的視訊聊天就不可能,因為其它瀏覽器並不是一個已知的網頁伺服器,所以使用者不知道需要建立視訊聊天的 IP 地址。所以,需要更多的技術以建立 p2p 連線。

防火牆和 NAT 穿透

一般電腦是不會被分配一個靜態公共 IP 地址的。原因是電腦是位於防火牆和網路訪問轉換裝置(NAT) 後面的。

一個 NAT 裝置會把防火牆內的私有 IP 地址轉換為一個公共 IP 地址。對於安全和有限的可用公共 IP 地址來說,NAT 裝置是必須的。這也是為什麼開發者的網頁程式不能夠把當前裝置看成擁有一個靜態公共 IP 地址的原因。

讓我們來了解下 NAT 裝置的工作原理。當開發者處於一個企業網中然後加入了 WIFI,那麼電腦將會被分配一個只存在於 NAT 後面的 IP 地址。假設是 172.0.23.4。然而,對於外部而言,使用者的 IP 地址會是類似 164.53.27.98 這樣的。那麼,外部會把所有請求看作來自 164.53.27.98 而 NAT 裝置會保證來自於目標使用者電腦的請求的響應資料返回到相應的內部 172.0.23.4 IP 地址的電腦。這得歸功於對映表。注意到除了 IP 地址,網路通訊還需要通訊埠。

隨著 NAT 裝置參與其中,瀏覽器需要知道進行通訊的目標瀏覽器對應的機器 IP 地址。

這個就需要用到 NAT 會話穿透程式(STUN)和 NAT 穿透中繼轉發伺服器。為使用 WebRTC 技術,開發者需要請求 STUN 伺服器以獲得其公共 IP 地址。這就好像你的電腦請求遠端伺服器,詢問遠端伺服器發起查詢的客戶端 IP 地址。遠端伺服器會返回對應的客戶端 IP 地址。

假設這一過程進展順利,那麼開發者將會獲得一個公共 IP 地址和埠,這樣就可以告知其它點如何直接和你進行通訊。同理,這些點也可以請求 STUN 或 TURN 伺服器以獲得公共 IP 地址然後告知其通訊地址。

信令,會話和協議

前述網路資訊檢索過程只是更大的信令話題的一部分,在 WebRTC 中,它是基於 JavaScript 會話構建協議(JSEP)標準的。信令涉及網路檢索和 NAT 穿透,會話建立及管理,通訊安全,媒體功能後設資料和調製及錯誤處理。

為了讓通訊順利進行,節點必須確定後設資料本地媒體環境(比如解析度和編碼能力等)和收集可用的程式主機網路地址。WebRTC 介面裡面沒有整合反覆傳輸這一重要資訊的信令機制。

WebRTC 標準並沒有規定信令且沒有在介面中實現是為了能夠更加靈活地使用其它技術和協議。信令和處理信令的伺服器是由 WebRTC 程式開發者控制的。

假設開發者基於瀏覽器的 WebRTC 程式使用之前所說的 STUN 伺服器獲取其公共 IP 地址,那麼,下一步即和其它點進行協商和建立網路會話連線。

使用任意一個專門應用於多媒體通訊的信令/通訊協議初始化會話協商和通訊連線。該協議負責管理會話和中斷的規則。

會話初始協議(SIP) 是協議之一。多虧了 WebRTC 信令的靈活性,SIP 並不是唯一可供使用的信令協議。所選的通訊協議必須和被稱為會話描述協議(SDP)的應用層協議相容,SDP 被應用於 WebRTC。所有的多媒體指定後設資料都是通過 SDP 協議進行資料傳輸的。

任意試圖和其它點進行通訊的點(比如 WebRTC 程式)都會生成互動式連線建立協議(ICE)候選集。候選集表示一個可供使用的 IP 地址,埠及傳輸協議的集合。注意,一臺電腦可以擁有多個網路介面(有線和無線等),因此可以擁有多個 IP 地址,每個介面分配一個 IP 地址。

以下為 MDN 上描繪這一通訊交換的圖示:

WebRTC 及點對點網路通訊機制

建立連線

每個節點首先獲取之前所說的公共 IP 地址。之後動態建立「通道」信令資料來檢索其它節點並且支援點對點協商及建立會話。

這些「通道」不能夠被外部檢索和訪問到且只能通過唯一識別符號來訪問。

需要注意的是由於 WebRTC 的靈活性且事實上信令建立程式並沒有在標準中指定,使用的技術不同,「通道」的概念和使用會有些許異同。事實上,一些協議並不要求「通道」機制來進行通訊。

本篇文章將會假設存在「通道」。

一旦兩個或者更多的點連線到相同的「通道」上,節點就可以進行通訊和協商會話資訊。這一過程和釋出/訂閱模式有些許類似。大體上,初始點使用諸如會話初始協議(SIP)和 SDP 的訊號協議發出一個「offer」的包。發起者等待連線到指定「通道」的接收者的「answer」應答。

一旦接收到應答,會開始選擇和協商由各個節點生成的最優互動連線建立協調候選(ICE)集。一旦選定了最優 ICE 候選集,特別是確認了所有節點通訊所要求的後設資料,網路路由(IP 地址和埠)及媒體資訊。這樣就會完全建立及啟用節點間的網路套接字會話。緊接著,每個節點建立本地資料流和資料通道端點,然後,最後使用任意雙向通訊技術來傳輸多媒體資料。

如果確認最優 ICE 候選的過程失敗了,這樣的情況經常發生於使用的防火牆和 NAT 技術,後備使用 TURN 伺服器作為中繼轉發伺服器。這一過程主要是使用一臺伺服器作為中間媒介,然後在節點間轉發傳輸資料。請注意這不是真正的點對點通訊,因為真正的點對點通訊是節點之間直接進行雙向資料傳輸。

每當使用 TURN 作為後備通訊的時候,每個節點將不必知道如何連線並傳輸資料給對方節點。相反,節點只需要知道在會話通訊期間實時傳送和接收多媒體資料的公共 TURN 伺服器。

需要重點理解的是這僅僅只是一個失敗保護和最後手段。TURN 伺服器需要相當健壯,擁有昂貴頻寬和強大的處理能力及處理潛在的大量資料。因此,使用 TURN 伺服器會明顯增加額外的開銷和複雜度。

WebRTC 介面

WebRTC 中包含三種主要介面:

  • **媒體捕捉和流-**允許開發者訪問諸如麥克風和網路攝像機的輸入裝置。該介面允許開發者獲取麥克風或者網路攝像機媒體流。
  • **RTCPeerConnection-**開發者實時傳輸獲取的視訊和音訊流到另一個 WebRTC 端點。開發者使用這些介面連線本地機器和遠端節點。該介面提供建立到遠端節點的連線,維護和監視連線及關閉不再活躍的連線的方法。
  • **RTCDataChannel-**該介面允許開發者傳輸任意資料。每個資料通道都和 RTCPeerConnection 有關。

我們將分別介紹這三類介面。

媒體捕捉和流

媒體捕捉和流介面經常被稱為媒體流介面或者流介面,該介面支援音訊或者視訊資料流資料,處理音視訊流的方法,與資料型別相關的約束,非同步獲取資料時的成功和錯誤回撥及 API 呼叫過程中觸發的事件。

MediaDevicesgetUserMedia() 方法提示使用者授權允許使用媒體輸入裝置,建立一個包含指定媒體型別軌道的媒體流。該媒體流,可包括諸如視訊軌道(由諸如攝像機,視訊錄製裝置,螢幕共享服務等硬體或者虛擬視訊源所建立),音訊軌道(與視訊類似,由諸如麥克風,A/D 轉換器等的物理或者虛擬音訊源所建立)且有可能是其它型別軌道。

該方法返回一個 Promise 並解析為 MediaStream 物件。當使用者拒絕授權或者沒有可用的匹配媒體資源,promise 會分別返回 PermissionDeniedError 或者 NotFoundError。

可以通過 navigator 物件訪問 MediaDevice 單例:

navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
 /* 使用流 */
})
.catch(function(err) {
 /* 處理錯誤 */
});
複製程式碼

注意這裡需要傳入 constraints 物件以指定返回的媒體流型別。開發者可以進行各種配置,包括使用的攝像頭(前置或後置),幀頻率,解析度等等。

從版本 25 起,基於 Chromium 的瀏覽器已經允許通過 getUserMedia() 獲取的音訊資料賦值給音訊或者視訊元素(但需要注意的是媒體元素預設值為空)。

可以把 getUserMedia作為網頁音訊介面的輸入節點

function gotStream(stream) {
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    var audioContext = new AudioContext();
    // 從流建立音訊節點
    var mediaStreamSource = audioContext.createMediaStreamSource(stream);
    // 把它和目標節點進行連線讓自己傾聽或由其它節點處理
    mediaStreamSource.connect(audioContext.destination);
}

navigator.getUserMedia({audio:true}, gotStream);
複製程式碼

隱私限制

由於該介面可能導致明顯的隱私問題,規範在通知使用者和許可權管理方面對 getUserMedia() 方法有非常明確的規定。在開啟諸如使用者網頁攝像頭或者麥克風的媒體輸入裝置的時候getUserMedia() 必須總是獲取使用者的授權。

瀏覽器可能提供每個域名授權一次的許可權功能,但必須至少第一次詢問授權,然後使用者必須指定授權的許可權。

通知中的規則同樣重要。除了可能存在其它硬體指示器,瀏覽器還必須顯示一個視窗顯示使用中的攝像頭或者麥克風。即使當時裝置沒有進行錄製,瀏覽器必須顯示一個提示視窗提示已授權使用哪個裝置作為輸入裝置。

RTCPeerConnection

RTCPeerConnection 表示一個本地電腦和遠端節點之間的 WebRTC 連線。它提供了連線遠端節點,維護和監視連線及關閉不再活躍的連線的方法。

如下為一張 WebRTC 圖表展示 了 RTCPeerConnection 的角色:

WebRTC 及點對點網路通訊機制

從 JavaScript 方面看 ,圖中需要理解的主要方面即 RTCPeerConnection 把複雜的底層內部結構的複雜度抽象為一個介面給開發者。WebRTC 所使用的編碼和協議為即使在不穩定的網路環境下仍然能夠建立一個儘可能實時的通訊而做了大量的工作:

  • 包丟失恢復
  • 迴音消除
  • 網路自適應
  • 視訊抖動緩衝
  • 自動增益控制
  • 噪聲減少和壓制
  • 影象「清潔」

RTCDataChannel

不僅僅是音視訊,WebRTC 還支援實時傳輸其它型別的資料。

RTCDataChannel 介面允許點對點交換任意資料。

該介面有許多用途,包括:

  • 遊戲
  • 實時文字聊天
  • 檔案傳輸
  • 分散式網路

該介面有幾項功能,充分利用 RTCPeerConnection 並建立強大和靈活的點對點通訊:

  • 使用RTCPeerConnection 建立會話
  • 包含優先順序的多個併發通道
  • 可靠和不可靠訊息傳遞語義
  • 內建安全(DTLS)和訊息堵塞控制

語法和已有的 WebSocket 類似,包含有 send() 方法和 message 事件:

var peerConnection = new webkitRTCPeerConnection(servers,
    {optional: [{RtpDataChannels: true}]}
);

peerConnection.ondatachannel = function(event) {
    receiveChannel = event.channel;
    receiveChannel.onmessage = function(event){
        document.querySelector("#receiver").innerHTML = event.data;
    };
};

sendChannel = peerConnection.createDataChannel("sendDataChannel", {reliable: false});

document.querySelector("button#send").onclick = function (){
    var data = document.querySelector("textarea#send").value;
    sendChannel.send(data);
};
複製程式碼

由於通訊是直接在瀏覽器之間進行的,所以 RTCDataChannel 會比 WebSocket 更快即使是使用中繼轉發伺服器(TURN)。

WebRTC 實際應用

在實際應用中,WebRTC 需要伺服器,但這很簡單,因此會發生如下步驟:

  • 使用者各自檢索節點然後交換諸如名字的詳情。
  • WebRTC 客戶端程式(點)交換網路資訊。
  • 點交換諸如視訊格式和解析度的媒體資訊。
  • WebRTC 客戶端程式穿透 NAT 閘道器 和防火牆。

換句話說,WebRTC 需要四種型別的服務端功能:

  • 使用者檢索和通訊
  • 發訊號
  • NAT/防火牆穿透
  • 中繼轉發伺服器以防點對點通訊失敗

ICE 使用 STUN 協議及其擴充套件 TURN 協議來建立 RTCPeerConnection 連線來處理 NAT 穿透和其它網路變化。

如前所述,ICE 是用來連線諸如兩個視訊聊天客戶的節點協議。一開始,ICE 會試圖使用最低的可能的網路延遲即使用 UDP 來直接連線節點。在這一過程中,STUN 伺服器只有一個任務:讓位於 NAT 之後的節點能夠找到其公共地址和埠。開發者可以檢視一下可用的 STUN 伺服器(Google 也有一堆) 名單。

WebRTC 及點對點網路通訊機制

檢索連線候選

若 UDP 失敗,ICE 嘗試 TCP,先 HTTP 後 HTTPS。如果直接連線失敗-特殊情況下,由於企業 NAT 穿透和防火牆-ICE 使用中間(轉發) TURN 伺服器。換句話說,ICE 首先通過 UDP 使用 STUN 伺服器來直接連線節點,若失敗則後備使用 TURN 中繼轉發伺服器。「檢索連線候選者」指的是檢索網路介面和埠的過程。

WebRTC 及點對點網路通訊機制

安全性

實時通訊程式或者外掛可能造成幾種安全問題。例如:

  • 未加密媒體或者資料有可能會在瀏覽器之間或者瀏覽器和伺服器之間被竊取。
  • 程式有可能在未經使用者授權同意的情況下記錄和分發音視訊。
  • 可疑軟體或者病毒有可能會隨著表面上無害的外掛或者程式一起安裝。

WebRTC 有幾種方法用來解決如上問題:

  • WebRTC 實現使用諸如 DTLSSRTP 的安全協議。
  • 包括信令機制在內的所有 WebRTC 元件都是強制加密的。
  • WebRTC 不是一個外掛:其元件執行於瀏覽器沙箱之中且不是在一個單獨的程式之中,不需要單獨安裝元件且隨著瀏覽器升級而更新。
  • 攝像頭和麥克風必須顯式授權且當攝像頭或者麥克風執行時,必須在使用者視窗中有所顯示。

對於需要實現一些瀏覽器之間實時通訊流功能的產品而言,WebRTC 是一個令人難以置信和強大的技術。

參考資料:

招賢納士

今日頭條招人啦!傳送簡歷到 likun.liyuk@bytedance.com ,即可走快速內推通道,長期有效!國際化PGC部門的JD如下:c.xiumi.us/board/v5/2H…,也可內推其他部門!

本系列持續更新中,Github 地址請查閱這裡

相關文章