零基礎快入門WebRTC:基本概念、關鍵技術、與WebSocket的區別等

移動端im技術分享 發佈 2024-01-16T22:16:40.840796+00:00

本文引用自Hussein Nasser的兩個視頻分享,原文內容由盧冰聰翻譯整理,即時通訊網收錄時有大量修訂和重新排版。1、內容概述本文是專為學習開源實時音視頻工程WebRTC的入門者編寫的速成指南。

本文引用自Hussein Nasser的兩個視頻分享,原文內容由盧冰聰翻譯整理,即時通訊網收錄時有大量修訂和重新排版。

1、內容概述

本文是專為學習開源實時音視頻工程WebRTC的入門者編寫的速成指南。

本文主要分享了WebRTC的基本概念、關鍵技術術語(包括NAT、STUN、TURN、ICE、SDP 和信令),著重講解了WebRTC是如何實現P2P通信以及WebRTC信令的作用,同時討論了WebRTC在技術上的優勢和劣勢,最後還提供了一個簡單的WebRTC Demo代碼。

2、什麼是WebRTC?

WebRTC(全稱 Web Real-Time Communication),即網頁實時通信。 是一個支持網頁瀏覽器進行實時語音對話或視頻對話的技術方案。從前端技術開發的視角來看,是一組可調用的API標準。這個技術可以使很多不同的應用,如視頻會議、文件傳輸、聊天和桌面共享等都不需要額外的插件。

在WebRTC發布之前,開發實時音視頻交互應用的成本是非常昂貴,需要考慮的技術問題很多,如音視頻的編解碼問題,數據傳輸問題,延時、丟包、抖動、回音的處理和消除等,如果要兼容瀏覽器端的實時音視頻通信,還需要額外安裝插件。

2010年5月:Google以6820萬美元收購VoIP軟體開發商Global IP Solutions的GIPS引擎,並改為名為「WebRTC」(見《了不起的WebRTC:生態日趨完善,或將實時音視頻技術白菜化》)。旨在建立一個網際網路瀏覽器間的實時通信的平台,讓 WebRTC技術成為 H5標準之一。

2012年1月:谷歌已經把這款軟體集成到Chrome瀏覽器中,Opera初步集成WebRTC。

2013年 6月:Mozilla Firefox發布22.0版本正式集成及支持WebRTC。

2017年11月:W3C WebRTC 1.0 草案正式定稿。

2021年1月:WebRTC 被 W3C 和 IETF 發布為正式標準(見《WebRTC 1.0: Real-Time Communication Between Browsers》)。

截止目前,WebRTC 是完全開源免費的,其使用 RTP 協議來傳輸音視頻,並支持 Chrome、Mozilla、Opera、Microsoft Edge、安卓瀏覽器等瀏覽器。

本節內容引用自《實時音視頻入門學習:開源工程WebRTC的技術原理和使用淺析》一文)

3、為什麼需要WebRTC?

3.1我們為何要建立 WebRTC?

建立它的理由是人們需要用一種標準的、低延遲的方式來傳遞媒體數據(視頻&音頻)。

所謂「標準的」意味著我們需要簡單易使用的 API。而所謂「低延遲的」意味著需要一種合適的協議,UDP 顯然是一個好的選擇,因為 UDP 沒有過多的應答過程(Acknowledgment)。但我們需要的協議要比 UDP 更好,要能支持 P2P 的通信。因為一旦依賴伺服器來傳遞內容就會因為反向代理或者穿透引入額外的延遲,用戶需要進行終止、觀察、處理、轉化流等操作,這些都會造成額外消耗。對於視頻傳輸、特別是直播、會話等場景,用戶希望內容到達得越快越好,所以 P2P 是最快的路徑。

此外,WebRTC 也旨在實現瀏覽器之間豐富的溝通。瀏覽器已經發展了很長時間,它「擁有」大量的優質資源,它可以訪問攝像頭和麥克風,這些特性都值得被開發利用。用戶不需要寫自己的應用,而是基於 WebRTC 的標準 API 便可以輕鬆使用。不僅是瀏覽器,在行動裝置和 IoT 設備通信時也同樣。

3.2在 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 就是這樣工作的:

4、WebRTC 的關鍵技術和概念

4.1概述

接下來我們將對 WebRTC 的各項關鍵技術和概念進行初始理解,對細節內容進行講述。

首先我們來了解 NAT 的細節(學習 WebRTC 是如何進行正確的網絡地址轉換),其次了解為什麼我們需要 STUN 和 TURN,此外還會介紹 ICE、SDP 以及信令交換的相關內容。

4.2NAT(Network Address Translation)

如果你有一個公開的 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 的轉換方式主要有以下幾種:

1)一對一 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 或者其他任何地址。

2)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 埠進行的通信。

3)埠受限型 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 埠進行的通信。

4)對稱 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。

在默認情況下:WebRTC 可以支持前三種 NAT 方式,對最後一種並不友好。實際上 90% 以上的通信就是通過前三種方式完成的,最後一種作者個人認為沒有使用的價值。

如果你對P2P技術感興趣,可以繼續深入閱讀以下幾篇:

《P2P技術詳解(一):NAT詳解——詳細原理、P2P簡介》

《P2P技術詳解(二):P2P中的NAT穿越(打洞)方案詳解(基本原理篇)》

《P2P技術詳解(三):P2P中的NAT穿越(打洞)方案詳解(進階分析篇)》

《通俗易懂:快速理解P2P技術中的NAT穿透原理》

4.3STUN(Session Traversal Utilities for NAT)

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 工作原理與之類似。

以下是部分 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

4.4 TURN(Traversal Using Relays around NAT)

在應用 Symmetric NAT 的情況下,必須使用 TURN。

所有的通信內容都要經過 TURN 伺服器的轉發,所以 TURN 伺服器的維護成本比較高,這也是為什麼幾乎沒有人免費提供這種伺服器供用戶使用。

下圖是一個 TURN 伺服器工作流程的示例,二者之間並不是直接的 P2P 通信,所有的信息都經過了 TURN 伺服器進行轉發。

這裡有一個開源庫也可以幫助大家創建屬於自己的 TURN 伺服器,地址是:https://github.com/coturn/coturn。

4.5ICE(Interactive Connectivity Establishment)

在建立了很多 STUN 和 TURN 伺服器後,從 A 到 B 之間的路徑有了非常多的選擇,為了更好的處理這些路徑,人們提出了 ICE。

ICE 會收集所有可用的通信路徑作為「候選人」(ICE Candidates),有可能是本地 IP 地址、STUN 和 TURN 伺服器提供的地址等等。收集到的所有地址都將放入 SDP 中,再送到對端,對端通過解析 SDP 來了解我方提供的重要信息。

因此,ICE 是 WebRTC 中非常關鍵的組成部分。

最後:如果想更多地了解STUN、TURN、ICE,可以閱讀:《P2P技術詳解(四):P2P技術之STUN、TURN、ICE詳解》。

4.6SDP(Session Description Protocol)

SDP 是一種用於表述 ICE Candidates 的格式,它描述了網絡選項、媒體選項、安全選項和其他很多信息,開發者甚至可以自定義 SDP 內容。

實際上 SDP 並不是一種協議,只是一種數據格式,但 SDP 是 WebRTC 中最重要的幾個概念之一。它的設計目的是將用戶產生的 SDP 送至其他端,送的方式並不關心。

4.7Signaling(信令交換)

Signaling 過程是將用戶產生的 SDP 通過某種方式傳遞給想要通信的那方。

如上所述,以何種方式傳遞並不重要。很多人通過 WebSocket 或者 socket.io 來傳遞 SDP 信息,這個過程就是 Signal SDP。

儘管要找到所有的 ICE candidate 是耗費時間的,但一旦完成了這個過程,下一步就是創建一個 SDP,進而生成一個 QR code 並把 QR code 公布到 twitter 上,其他人掃描了這個二維碼就可以獲取相應的 SDP。

這個過程是通過 twitter、QR code、Whatsapp、WebSockets、還是 HTTP 請求都不重要,因為實際上就是將一個長字符串傳遞給其他人罷了。

簡而言之,Signaling 就是將 SDP 信息傳遞給另外一方。

4.8小結一下

一個典型的WebRTC通信流程是這樣的:

  • 1)A 想要和B建立連接;
  • 2)A 創建了一個 offer,它尋找所有的 ICE candidate、安全選項、音視頻選項等並創建 SDP(簡單來說這個 offer 就是 SDP);
  • 3)A 將 SDP 信令傳遞給 B(Signaling);
  • 4)B 根據 A 的 offer 進行設置,並創建應答(answer);
  • 5)B 將 Answer 信令傳遞給 A(Signaling);
  • 6)連接建立。

5、WebRTC 的信令(Signal)

5.1什麼是信令

信令是配置、控制、以及結束用戶間通信會話的過程。端到端通信(即P2P)需要信令來建立。

兩端想要通信,主要需要三個信令步驟:

  • 1)分享會話控制信息;
  • 2)交換IP位址和埠等網絡信息;
  • 3)交換用戶的編解碼器以及媒體格式。

5.2為什麼通信需要信令

那麼為什麼通信需要信令呢:

  • 1)會話控制信息會控制端到端連接的所有建連、斷連、以及發送信息;
  • 2)IP 以及埠信息用於找到用戶網絡層位置;
  • 3)編解碼器以及多媒體格式用於確定用戶間建立的解析度以及多媒體設置;
  • 4)這些所有的設置都根據 SDP 協議(Session Description Protocal)來進行交換。

5.3為什麼 WebRTC 需要信令

如果兩個用戶希望P2P通信,那兩端之間則需要一個額外的伺服器來交換初始數據設置 WebRTC 連接,這個伺服器就叫做信令伺服器。

信令過程結束後,所有多媒體數據都會經過 RTCPeerconnection 端到端交換。

知識要點:

  • 1)信令伺服器只是幫助 WebRTC 交換元數據來建立連接,並不真的對 WebRTC 過程影響;
  • 2)信令伺服器可以由任意的伺服器技術搭建,如 WebSocket、socket.io、SIP 等;
  • 3)RTCPeerConnection 是 WebRTC 使用的 API 來建立用戶間連接並通信。

5.4如何讓用戶實現P2P通信

用戶間想要獲取各自的公網 IP 地址,因為 NAT 和防火牆導致兩個用戶直接通信是很困難的,因此需要通過 ICE框架配合 STUN和 TURN協議來解決這些問題,實現端到端連接。

STUN的作用:如果一個用戶在 NAT 背後有一個區域網 IP 地址,那從這個區域網外很難聯繫到這個用戶,那這個用戶就可以通過 STUN 伺服器來獲取他的公網 IP,就可以讓其他公網的用戶來穿透 NAT 連接到他。

TURN的作用:STUN 使用的方法在面對對稱型 NAT 時就會失效,這時就需要使用 TURN 協議。但是 TURN 的問題在於,STUN 在連接建立完成後就不再被需要,而 TURN 則在整個會話過程中都需要存在。

5.5WebRTC 的信令是必須的嗎

WebRTC 可以讓用戶直接P2P通信,但是卻沒有辦法讓其中一個用戶找到另一個用戶(如 IP 地址等)。因此用戶也可以使用 SDP 請求和 SDP 答覆,只需要有一個信令伺服器就可以了。

5.6SDP 請求和答覆

在兩端希望直接通信之前,他們必須都要有一個連接到一個信令伺服器,這樣就可以兩端分享 SDP 信息。

SDP 請求和答覆包括用戶有關音頻、視頻、編碼器等信息。一個用戶發送一個初始的 SDP 請求來創建多媒體通信會話,對端收到後可以選擇創建一個 SDP 答覆來接受或拒絕這個 SDP 請求。

6、WebRTC 的架構原理

下圖是一個簡單的 WebRTC 連接架構原理圖:

在連接階段,用戶使用信令伺服器間接通信建立連接,在連接建立結束後,兩用戶直接通過音視頻信道通信。

下圖是一個詳細版本的 WebRTC 連接架構原理圖:

如上圖所示:可以看到兩個用戶希望建立 WebRTC 連接,兩端直接建立連接前都可以連接到同一個信令伺服器,並通過該伺服器交換 SDP 信息。在 SDP 請求和答覆交換結束後,兩用戶都可以獲取各自的 IP 地址和音視頻配置等信息。之後就需要用 TURN 或者 STUN 伺服器來穿透 NAT,達到用戶間的直接 WebRTC 連接。

7、WebRTC 的優缺點

7.1優點

1)P2P 通信是非常棒的:對於高帶寬內容可以有降低的延遲。P2P 是最快的路徑,不需要經過其他的第三方進行通信。即使通網際網路傳輸要經過大量的路由器,但如果內容已經被加密了所有的路由器都不會查看內容,它們會直接傳遞數據包,所以 P2P 是非常好的通信方式。對於高帶寬內容,它們通過 UDP 直接被「送入」和「推出」,通過 P2P UDP 傳遞這些內容(特別是視頻內容),用戶將收穫最好的性能。

2)標準可用的 API:WebRTC 有一套非常標準、非常優雅的 API,可以直接在瀏覽器中應用,不需要安裝其他的包、也不需要用多餘的開發工具。

7.2缺點

1)需要維護 STUN 和 TURN 伺服器:在某些情況下 P2P 不能工作,你仍需要一個 TURN 伺服器。但維護 STUN 和 TURN 伺服器需要耗費大量的人力物力,特別是 TURN 伺服器。因為你首先要花錢維護一個 Public IP,並且必須維護這個伺服器使其可以正常啟動和運行。作者個人認為與其花費這種代價,不如自己建立一個擁有全部控制權的伺服器,進行反向代理。

2)在參與者過多的情況下P2P 會崩潰:假設有 100 個人想要相互交流,你會創建 P2P 連接嗎?那會是幾百乘幾百的連接量,因為每個人都需要連接到其他任何一個用戶,這將是非常大規模的。但如果你有一個集中式伺服器,每個用戶只需要和這個伺服器建立一個連接,你可以通過這個伺服器控制所有的流量,這明顯是一種更好的方式。所以 WebRTC 有時候無法用在遊戲上,你沒辦法利用 WebRTC 來創建一個多用戶遊戲,當然 3 個用戶是可以的,但幾百個用戶作者認為是無法實現的。

8、WebSocket 和 WebRTC 的區別

8.1設計初衷不同

瀏覽器通信有主要兩種傳輸信道:HTTP 和 WebSockets。WebSocket 的作用就是用於實現瀏覽器的雙向機制通信。

對於HTTP:主要用於獲取網頁內容,文字或圖片等,是一種客戶服務類型協議,其中瀏覽器是客戶端,而網頁伺服器是服務端;

而對於 WebSocket:瀏覽器通過一個 WebSocket 連接到網頁伺服器,與 HTTP 相同也是一個C/S類型協議。但是 HTTP 是一個單向的信道,而 WebSocket 是雙向的,意味著伺服器和客戶端之間的連接可以一直保持到兩者主動斷開。

WebSocket 主要用於實時網頁應用和IM聊天應用等。

而 WebRTC 相較於 WebSocket 的特點在於:

  • 1)WebRTC 是為高質量音視頻實時通信設計的;
  • 2)WebRTC 提供的瀏覽器端到端通信遠比 WebSocket 提供的服務延遲更低。

8.2實現上的區別

主要是兩點:

  • 1)WebRTC 使用 UDP 協議,而 WebSocket 使用 TCP 協議;
  • 2)WebRTC 可以同時提供高質量且低延遲的推流。

8.3WebRTC 其實也使用了 WebSocketk

WebRTC 其實也使用了 WebSocket,不過是用於搭建 WebRTC的信令機制,但是在連接建立結束後,由於 WebRTC 是端到端連接,因此也不再需要額外伺服器。

9、一個簡單的 WebRTC Demo

為了配合本文內容的理解,這裡準備了一個簡單的WebRTC Demo代碼(下載地址點此)。

這個 Demo 程序可以實現:

  • 1)在兩個瀏覽器間進行通信(瀏覽器 A 和瀏覽器 B);
  • 2)A 創建一個 offer(SDP),並設置它為本地描述;
  • 3)B 接收一個 offer 並設置它為遠端描述;
  • 4)B 創建一個 answer 並設置它為本地描述,並將其傳遞給 A;
  • 5)A 接收 answer 並設置它為遠端描述;
  • 6)建立連接、建立數據通道、交換數據。

10、參考資料

[1] Get started with WebRTC

[2] 零基礎,史上最通俗視頻編碼技術入門

[3] 零基礎入門:實時音視頻技術基礎知識全面盤點

[4] 良心分享:WebRTC 零基礎開發者教程(中文)[附件下載]

[5] WebRTC實時音視頻技術的整體架構介紹

[6] 新手入門:到底什麼是WebRTC伺服器,以及它是如何聯接通話的?

[7] WebRTC實時音視頻技術基礎:基本架構和協議棧

[8] 開源實時音視頻技術WebRTC在Windows下的簡明編譯教程

[9] 零基礎入門:基於開源WebRTC,從0到1實現實時音視頻聊天功能

[10] 實時音視頻入門學習:開源工程WebRTC的技術原理和使用淺析

[11] WebSocket從入門到精通,半小時就夠!

[12] 搞懂現代Web端即時通訊技術一文就夠:WebSocket、socket.io、SSE

[13] NAT詳解——詳細原理、P2P簡介

[14] P2P技術之STUN、TURN、ICE詳解

[15] 通俗易懂:快速理解P2P技術中的NAT穿透原理

學習交流:

- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》

- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK(備用地址點此)

(本文已同步發布於:http://www.52im.net/thread-4184-1-1.html)

關鍵字: