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