WebRTC 及點對點網絡通訊機制

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

這是 JavaScript 工做原理第十八章。html

概述

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

WebRTC 填補了網頁開發平臺中的一個重要空白。在以往,只有諸如桌面聊天程序這樣的 P2P 技術纔可以實現實時通信而網頁不行。可是 WebRTC 的出現改變了這一情況。java

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

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

點對點通訊

每一個用戶的網頁瀏覽器必須按照以下步驟以實現經過網頁瀏覽器進行的點對點通訊:github

  • 贊成開始進行通訊
  • 知道如何定位另外一個點
  • 繞過安全和防火牆限制
  • 實時傳輸全部多媒體通訊信息

衆所周知,基於瀏覽器的點對點通訊的最大挑戰之一即如何定位和創建與另外一個網頁瀏覽器進行通訊的網絡套接字以進行雙向數據傳輸。咱們將會克服創建與此種網絡鏈接相關的困難。web

每當網頁程序須要數據或者靜態資源,會直接從相應的服務器獲取,僅此而已。可是,若是若想要經過直接鏈接用戶的瀏覽器來創建點對點的視頻聊天就不可能,由於其它瀏覽器並非一個已知的網頁服務器,因此用戶不知道須要創建視頻聊天的 IP 地址。因此,須要更多的技術以創建 p2p 鏈接。promise

防火牆和 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 上描繪這一通訊交換的圖示:

創建鏈接

每一個節點首先獲取以前所說的公共 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 的角色:

從 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 也有一堆) 名單。

檢索鏈接候選

若 UDP 失敗,ICE 嘗試 TCP,先 HTTP 後 HTTPS。若是直接鏈接失敗-特殊狀況下,因爲企業 NAT 穿透和防火牆-ICE 使用中間(轉發) TURN 服務器。換句話說,ICE 首先經過 UDP 使用 STUN 服務器來直接鏈接節點,若失敗則後備使用 TURN 中繼轉發服務器。「檢索鏈接候選者」指的是檢索網絡接口和端口的過程。

安全性

實時通訊程序或者插件可能形成幾種安全問題。例如:

  • 未加密媒體或者數據有可能會在瀏覽器之間或者瀏覽器和服務器之間被竊取。
  • 程序有可能在未經用戶受權贊成的狀況下記錄和分發音視頻。
  • 可疑軟件或者病毒有可能會隨着表面上無害的插件或者程序一塊兒安裝。

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

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

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

參考資料:

招賢納士

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

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

相關文章
相關標籤/搜索