目錄
1. WebRTC 概述
2. WebRTC 揭秘
2.1 Network Address Translation: NAT
2.2 Session Traversal Utilities for NAT:STUN
2.3 Traversal Using Relays around NAT: TURN
2.4 Interactive Connectivity Establishment: ICE
2.5 Session Description Protocol: SDP
2.6 信令交換:Signaling
工作流程總結
3. Demo
4. WebRTC的優缺點
1. 優點
2. 缺點
5. 擴展內容
5.1 Media API
5.2 onIceCandidate 和 addIceCandidate
5.3 自定義 TURN 和 STUN 服務器
5.4 公共 STUN 服務器
WebRTC (Web Real-Time Communication)是一個免費、開源的項目,通過簡單的應用程序編程接口(API)為 Web 瀏覽器和移動應用程序提供實時通信(RTC)。這也表明了 WebRTC 設計的目標就是“設計一種通過盡量短的、延遲盡量低的路徑進行 P2P 通信的協議,提供一種簡單的、能讓所有人使用的 API”。一旦你把它放入瀏覽器,它就是標準;一旦它成為了標準,開發時會遇到的“摩擦”就會消失。
我追蹤 WebRTC 這項技術大概已經兩年了,聽眾們為我提供了大量優質的資源,也提出了很多優秀的問題。應大家的呼聲,我做出了這期視頻,為大家提供一個 WebRTC 的基本教程。我將按以下順序進行講解:
WebRTC 概述
WebRTC 揭秘:NAT、STUN、TURN、ICE、SDP、信令
Demo
WebRTC的優缺點
擴展內容
1. WebRTC 概述
首先想到的問題是我們為何要建立 WebRTC?
建立它的理由是人們需要用一種標準的、低延遲的方式來傳遞媒體數據(視頻&音頻)。所謂“標準的”意味著我們需要簡單易使用的 API;而所謂“低延遲的”意味著需要一種合適的協議,UDP 顯然是一個好的選擇,因為 UDP 沒有過多的應答過程(Acknowledgment)。但我們需要的協議要比 UDP 更好,要能支持 P2P 的通信。因為一旦依賴服務器來傳遞內容就會因為反向代理或者穿透引入額外的延遲,用戶需要進行終止、觀察、處理、轉化流等操作,這些都會造成額外消耗。對于視頻傳輸、特別是直播、會話等場景,用戶希望內容到達得越快越好,所以 P2P 是最快的路徑。
此外,WebRTC 也旨在實現瀏覽器之間豐富的溝通。瀏覽器已經發展了很長時間,它“擁有”大量的優質視頻,它可以訪問攝像頭和麥克風,這些特性都值得被開發利用。用戶不需要寫自己的應用,而是基于 WebRTC 的標準 API 便可以輕松使用。不僅是瀏覽器,在移動設備和 IoT 設備通信時也同樣。
那么在 WebRTC 中究竟發生了哪些事呢?
舉個例子,A 想要與 B 進行通信,但 A 與 B 之間“互不相識”。所以 A 首先需要找到所有 Public(不是 B)能連接到它的途徑,檢查 A 是否有一個公共 IP 能被 Public 識別或使用,如果沒有檢查 A 的路由器是否允許公開端口轉發規則、是否在路由上有公共代表等等。B 也做了以上同樣的事。
此外,A 和 B 還會收集自身所支持的加密方式、安全參數、視頻編解碼器等等大量的信息,注意這些信息還沒有被送到對端,在這個階段只是廣泛地收集。所有這些信息,構成了“SDP”。
接下來,A 和 B 會通過其他方式(可以是 WhatsApp、QR、Tweet、WebSockets、HTTP Fetch…)發出會話信息,這種方式具體是什么 WebRTC 并不關心,只要能從 A 到 B(B 到 A)就可以。
這種工作方式表面上是有些“愚蠢的”,部分人可能會認為“既然我已經有了 A 和 B 之間通信的線路,那還要 WebRTC 做什么呢?”但認真思考一下就可以發現,WebRTC 只要首次通信雙方交換了 SDP,后面就會實現真正的 P2P 通信,不再需要 WhatsApp、QR 等等中間途徑,不會有比這更快的通信路徑。因此最終 A 通過最優路徑連接到了 B,這就是 WebRTC 的工作流程。
更詳細的闡釋這個例子如下:
如上圖所示,假設 A 找到了 A1、A2、A3 三種方式可以訪問它,同時還找到了安全參數、媒體選項等信息。同時,B 也做了一樣的工作。接下來,他們通過一些方式(例如 WhatsApp)交換了以上信息。然后 A 找到 B2 是可用的最佳路徑,而 B 也發現 A1 是可用的最佳路徑,那么二者將通過這條路徑直接連接彼此。本質上 WebRTC 就是這樣工作的。
2. WebRTC 揭秘
接下來我們對 WebRTC 進行深入理解,對細節內容進行講述。首先了解 NAT 的細節,學習 WebRTC 是如何進行正確的網絡地址轉換;其次了解為什么我們需要 STUN 和 TURN;此外還會介紹 ICE、SDP 以及信令交換的相關內容。
2.1 Network Address Translation: NAT
如果你有一個公開的 Public IP 地址,連接過程將不會有什么問題。因為你會像 Web 服務器一樣一直監聽端口,把端口和 IP 都提供給對方后,你和它就可以直接進行連接了。但在大多數情況下,用戶都是隱藏在公共網絡之后的,無法直接連接。如下圖所示的示例中,路由器有一個 Public IP 5.5.5.5,也有一個 Private IP 10.0.0.1(也被稱為 gateway),你的機器只有一個 Private IP 10.0.0.2,但你想要訪問 IP 為 4.4.4.4:80 的機器,要如何實現呢?
首先你的機器會構建一個數據包,聲明想向 4.4.4.4:80 發出 GET 請求,10.0.0.2 是源 IP 地址。接下來,你的機器會通過子網掩碼判斷是否可以直接與 4.4.4.4:80 進行連接,運算結果會顯示 4.4.4.4:80 并不在你所在的子網中,因此無法直接進行通信。所以下一步就需要將請求發送給路由器,借助 gateway 進行通信。路由器會替換源 IP 地址和端口為 Public IP 和一個隨機端口,但在此之前會創建 NAT 表,來記錄三者之間的對應關系。這樣對端就能收到你的GET請求,并進行后續處理了。
在這之后,服務器 4.4.4.4:80 將向你的機器發送回復,工作原理和上述相同,根據 NAT 表查詢對應地址完成通信。
NAT 的轉換方式主要有以下幾種,在默認情況下,WebRTC 可以支持前三種 NAT 方式,對最后一種并不友好。實際上 90% 以上的通信就是通過前三種方式完成的,最后一種作者個人認為沒有使用的價值。
一對一 NAT(完全圓錐型 NAT):One to One NAT(Full-cone NAT)路由器上要發送到外部 IP:port 的數據包總是可以映射到內部 IP:port ,無一例外。舉例說明,所有發送到 5.5.5.5:3333 的數據包總是會被自動轉發到 10.0.0.2:8992,無論這個包是來自 4.4.4.4:80 或者其他任何地址。
IP 受限型 NAT:Address restricted NAT出于安全考慮,部分路由器會地址限制,考慮之前是否與該地址進行過通信。即路由器上要發送到外部 IP:port 的數據包可以映射到內部 IP:port,前提是數據包的源地址與 NAT 表相符,無所謂端口是什么。舉例說明,發送到 5.5.5.5:3333 的數據包中,只有源 IP 是 4.4.4.4 或其他表中有過記錄的 IP 才會被自動轉發到 10.0.0.2:8992,即使這個 IP 之前并不是和 3333 端口進行的通信。
端口受限型 NAT:Port restricted NAT與前者相比,增加了端口限制,即路由器上要發送到外部 IP:port 的數據包可以映射到內部 IP:port,前提是數據包的源 IP 和 Port 都要與 NAT 表相符。舉例說明,發送到 5.5.5.5:3333 的數據包中,只有來自 4.4.4.4:80 或其他表中有過記錄的 IP:Port 才會被自動轉發到 10.0.0.2:8992,即使這個 IP:Port 之前并不是和 3333 端口進行的通信。
對稱 NAT:Symmetric NAT該方式是限制最多的一種,即必須匹配完整的 IP:port,區別在于發送到 5.5.5.5:3333 的數據包中,只有來自 4.4.4.4:80 的才會被自動轉發到 10.0.0.2:8992,其他的包均無法通過。這種方式無法在 WebRTC 中使用,因為 WebRTC 需要 STUN 服務器。一旦 STUN 服務器建立了一個 Public 代表,Symmetric NAT 要求只能與一個特定的對端通信,這種限制不適合 WebRTC。
2.2 Session Traversal Utilities for NAT:STUN
STUN 是可以賦予一個應用程序所需要的 Public IP 和 Port,適用于 Full-cone、Address restricted 和 Port restricted NAT,無法用于 Symmetric NAT。STUN 服務器通常在 3478 端口上運行,TLS 端口為 5349。STUN 是非常輕量級的,用戶可以使用 docker 建立一個 STUN 服務器。STUN 服務器的目的就是讓用戶找到自己的 Public 表示,并通過這個 Public 表示與其他用戶進行通信。如果我們使用的是像大約 1996 年或 2000 年早期時那樣的 Public IP 地址,通信也將非常簡單。但就現在而言,我們必須使用 STUN 服務器。STUN 服務器的工作流程如下圖所示:
首先創建一個數據包進行 STUN 請求,STUN 服務器的地址為 9.9.9.9:3478,同樣在路由器創建了 NAT 表并進行了地址轉換,然后數據包被送到了 STUN 服務器。
服務器收到請求后,為 10.0.0.2 的機器構建了一個 Public 表示 5.5.5.5:3333,并把這個信息打包進一個數據包進行反饋。
上述是一個 STUN 請求的詳細過程,以下圖為例 STUN 在整個通信過程中進行了以下工作:首先給予 10.0.0.2 的機器一個 Public 表示 5.5.5.5:3333,同時給予 192.168.1.2 的機器一個 Public 表示 7.7.7.7:4444。隨后二者都使用獲得的 Public 表示進行連接。
值得注意的是,這二者之前并沒有進行過通信。如果是 Full-cone NAT,那么沒有問題可以連接;如果是 Address restricted NAT,第一個請求連接的請求將會失敗。在這種情況下,用戶需要通過服務器建立至少一個通信請求,先讓兩個地址都能保存在兩端的路由器中,這樣再次通過 Public 表示進行連接請求時就能找到匹配的地址,繼而可以完成連接。Port restricted NAT 工作原理與之類似。
2.3 Traversal Using Relays around NAT: TURN
在應用 Symmetric NAT 的情況下,必須使用 TURN。所有的通信內容都要經過 TURN 服務器的轉發,所以 TURN 服務器的維護成本比較高,這也是為什么幾乎沒有人免費提供這種服務器供用戶使用。下圖是一個 TURN 服務器工作流程的示例,二者之間并不是直接的 P2P 通信,所有的信息都經過了 TURN 服務器進行轉發。
2.4 Interactive Connectivity Establishment: ICE
在建立了很多 STUN 和 TURN 服務器后,從 A 到 B 之間的路徑有了非常多的選擇,為了更好的處理這些路徑,人們提出了 ICE。ICE 會收集所有可用的通信路徑作為“候選人”(ICE Candidates),有可能是本地 IP 地址、STUN 和 TURN 服務器提供的地址等等。收集到的所有地址都將放入 SDP 中,再送到對端,對端通過解析 SDP 來了解我方提供的重要信息。因此,ICE 是 WebRTC 中非常關鍵的組成部分。
2.5 Session Description Protocol: SDP
SDP 是一種用于表述 ICE Candidates 的格式,它描述了網絡選項、媒體選項、安全選項和其他很多信息,開發者甚至可以自定義 SDP 內容。實際上 SDP 并不是一種協議,只是一種數據格式,但 SDP 是 WebRTC 中最重要的幾個概念之一。它的設計目的是將用戶產生的 SDP 送至其他端,送的方式并不關心。
2.6 信令交換:Signaling
Signaling 過程是將用戶產生的 SDP 通過某種方式傳遞給想要通信的那方,如上所述,以何種方式傳遞并不重要。很多人通過 Websockets 或者 socket io 來傳遞 SDP 信息,這個過程就是 Signal SDP。盡管要找到所有的 ICE candidate 是耗費時間的,但一旦完成了這個過程,下一步就是創建一個 SDP,進而生成一個 QR code 并把 QR code 公布到 twitter 上,其他人掃描了這個二維碼就可以獲取相應的 SDP。這個過程是通過 twitter、QR code、Whatsapp、WebSockets、還是 HTTP 請求都不重要,因為實際上就是將一個長字符串傳遞給其他人罷了。簡而言之,Signaling 就是將 SDP 信息傳遞給另外一方。
工作流程總結
A 想要和B建立連接;
A 創建了一個 offer,它尋找所有的 ICE candidate、安全選項、音視頻選項等并創建 SDP,簡單來說這個 offer 就是 SDP;
A 將 SDP 信令傳遞給 B(Signaling);
B 根據 A 的 offer 進行設置,并創建應答(answer);
B 將 Answer 信令傳遞給 A(Signaling);
連接建立。
3. Demo
作者詳細講述了一個 Demo 程序的編寫,該程序可以:
在兩個瀏覽器間進行通信(瀏覽器 A 和瀏覽器 B);
A 創建一個 offer(SDP),并設置它為本地描述;
B 接收一個 offer 并設置它為遠端描述;
B 創建一個 answer 并設置它為本地描述,并將其傳遞給 A;
A 接收 answer 并設置它為遠端描述;
建立連接、建立數據通道、交換數據。
源碼:https://github.com/hnasr/javascript_playground/tree/master/webrtc
4. WebRTC的優缺點
1. 優點
P2P 通信是非常棒的,對于高帶寬內容可以有降低的延遲。P2P 是最快的路徑,不需要經過其他的第三方進行通信。即使通互聯網傳輸要經過大量的路由器,但如果內容已經被加密了所有的路由器都不會查看內容,它們會直接傳遞數據包,所以 P2P 是非常好的通信方式。對于高帶寬內容,它們通過 UDP 直接被“送入”和“推出”,通過 P2P UDP 傳遞這些內容(特別是視頻內容),用戶將收獲最好的性能。
標準可用的 APIWebRTC 有一套非常標準、非常優雅的 API,可以直接在瀏覽器中應用,不需要安裝其他的包、也不需要用多余的開發工具。
2. 缺點
需要維護 STUN 和 TURN 服務器在某些情況下 P2P 不能工作,你仍需要一個 TURN 服務器。但維護 STUN 和 TURN 服務器需要耗費大量的人力物力,特別是 TURN 服務器。因為你首先要花錢維護一個 Public IP,并且必須維護這個服務器使其可以正常啟動和運行。作者個人認為與其花費這種代價,不如自己建立一個擁有全部控制權的服務器,進行反向代理。
在參與者過多的情況下,P2P 會崩潰假設有 100 個人想要相互交流,你會創建 P2P 連接嗎?那會是幾百乘幾百的連接量,因為每個人都需要連接到其他任何一個用戶,這將是非常大規模的。但如果你有一個集中式服務器,每個用戶只需要和這個服務器建立一個連接,你可以通過這個服務器控制所有的流量,這明顯是一種更好的方式。所以 WebRTC 有時候無法用在游戲上,你沒辦法利用 WebRTC 來創建一個多用戶游戲,當然 3 個用戶是可以的,但幾百個用戶作者認為是無法實現的。
5. 擴展內容
5.1 Media API
getUserMedia 函數可以用于獲取麥克風和攝像頭,進而獲得一個流(stream),這個流的內容會通過RTCPConnection.addTrack(stream)送入 RTC 連接中。理論上你可以用數據通道傳遞任何類型的數據,但如果你想要傳遞媒體信息就要用到 stream,這些數據的傳遞將使用不同的協議。
更多內容可參考:https://www.html5rocks.com/en/tutorials/webrtc/basics/
5.2 onIceCandidate 和 addIceCandidate
這兩個函數可用于在新的 Candidate 加入或離開時維護連接。用戶每次從系統獲取一個 ICE Candidate 時,onIceCandidate 函數就會被調用。onIceCandidate 函數將告知用戶“在 SDP 已經被創建后,又有了新的 Candidate”。新的 Candidate 將被告知對端,告知的方式可以是 Signaling,也可以直接通過同一個 SDP 連接。對端通過 addIceCandidate 函數將新的 Candidate 加入 SDP。
5.3 自定義 TURN 和 STUN 服務器
在創建 RTCP 連接時,可以選擇傳遞配置信息,下圖為一個配置信息示例。基本上用戶可以自定義 ICE 服務器,其中有很多可選項。
此外,有一個開源庫也可以幫助大家創建屬于自己的 TURN 服務器,地址:https://github.com/coturn/coturn
5.4 公共 STUN 服務器
作者給出了部分 Google 提供的公共服務器,可供開發人員參考:
stun1.l.google.com:19302
stun2.l.google.com:19302
stun3.l.google.com:19302
stun4.l.google.com:19302
stun.stunprotocol.org:3478
審核編輯 :李倩
-
服務器
+關注
關注
12文章
9591瀏覽量
86947 -
WebRTC
+關注
關注
0文章
57瀏覽量
11484
原文標題:WebRTC 速成課程
文章出處:【微信號:livevideostack,微信公眾號:LiveVideoStack】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論