首頁>技術>

WebRTC是如何進行NAT穿越的呢?如果穿越不成功,我們又該如何保證使用者服務的呢?這些知識在本文中給出答案。

信令

WebRTC 信令控制的架構圖如下所示:

信令伺服器用於交換三種類型的資訊:

會話控制訊息

會話控制訊息比較簡單,像房間的建立與銷燬、加入房間、離開房間、開啟音訊/關閉音訊、開啟影片/關閉影片等等這些都是會話控制訊息。

對於一個真正商業的WebRTC信令伺服器,還有許多的會話控制訊息。像獲取房間人數、靜音/取消靜音、切換主講人、影片輪詢、白板中的畫筆、各種圖型等等。但相對來說都是一引起比較簡單的訊息。

在我們之前的例子中,服務端只處理了一個會話訊息 create or join,即房間的建立與加入訊息。程式碼如下:

...socket.on('create or join', function(room) {    var clientsInRoom = io.sockets.adapter.rooms[room];    var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;    if (numClients === 0) {      socket.join(room);      logger.debug('Client ID ' + socket.id + ' created room ' + room);      socket.emit('created', room, socket.id);    } else if (numClients === 1) {      io.sockets.in(room).emit('join', room);      socket.join(room);      socket.emit('joined', room, socket.id);      io.sockets.in(room).emit('ready');    } else { // max two clients      socket.emit('full', room);    }});  ...  

該程式碼的邏輯非常簡單,當收到 create or join 訊息後,判斷房間裡當前人數,如果房間裡的人數為 0,說明是第一個人進來,此時,需要向連線的客戶端傳送 created 訊息;如果房間裡的人數為 1,說明是第二個人進來,需要向客戶端傳送 joined訊息;否則傳送 full 訊息,說明房間已滿,因為目前一個房間最多隻允許有兩個人。

網路資訊訊息

網路資訊訊息用於兩個客戶端之間交換網路資訊。在WebRTC中使用 ICE 機制建立網路連線。

在WebRTC的每一端,當建立好 RTCPeerConnection 物件,且呼叫了setLocalDescription 方法後,就開始收集 ICE候選者 了。

在WebRTC中有三種類型的候選者,它們分別是:

主機候選者反射候選者中繼候選者

主機候選者,表示的是本地區域網內的 IP 地址及埠。它是三個候選者中優先順序最高的,也就是說在 WebRTC 底層,首先會償試本地區域網內建立連線。

反射候選者,表示的是獲取 NAT 內主機的外網IP地址和埠。其優先順序低於 主機候選者。也就是說當WebRTC償試本地連線不通時,會償試透過反射候選者獲得的 IP地址和埠進行連線。

其結構如下圖所示:

在上面這幅圖中可以看到,WebRTC透過 STUN server 獲得自己的外網IP和埠,然後透過信令伺服器與遠端的WebRTC交換網路資訊。之後雙方就可以償試建立 P2P 連線了。

以上就是我們通常所說的 P2P NAT 穿越。在WebRTC內部會探測使用者的 NAT 型別,最終採用不同的方法進行 NAT 穿越。不過,如果雙方都是 對稱NAT 型別,是無法進行 P2P NAT 穿越的,此時只能使用中繼了。

中繼候選者,表示的是中繼伺服器的IP地址與埠,即透過伺服器中轉媒體資料。當WebRTC客戶端通訊雙方無法穿越 P2P NAT 時,為了保證雙方可以正常通訊,此時只能透過伺服器中轉來保證服務質量了。

所以 中繼候選者的優先順序是最低的,只有上述兩種候選者都無法進行連線時,才會使用它。

socket.on('message', function(message) {     socket.broadcast.emit('message', message);});

客戶端接收到 message 訊息後,會做進一步判斷。如果訊息型別為 candidate,即 網路訊息信令時,會生成 RTCIceCandidate 物件,並將其新增到 RTCPeerConnection 物件中,從而使 WebRTC 在底層自動建立連線。 其程式碼如下:

socket.on('message', function(message) {  ...  } else if (message.type === 'candidate') {    var candidate = new RTCIceCandidate({      sdpMLineIndex: message.label,      candidate: message.candidate    });    pc.addIceCandidate(candidate);  } else if (...) {    ...  }});
交換媒體能力訊息

在WebRTC中,媒體能力最終透過 SDP 呈現。在傳輸媒體資料之前,首先要進行媒體能力協商,看雙方都支援哪些編碼方式,支援哪些解析度等。協商的方法是透過信令伺服器交換媒體能力資訊。

WebRTC 媒體協商的過種如上圖所示。

第一步,Amy 呼叫 createOffer 方法建立 offer 訊息。offer 訊息中的內容是 Amy 的 SDP 資訊。第二步,Amy 呼叫 setLocalDescription 方法,將本端的 SDP 資訊儲存起來。第三步,Amy 將 offer 訊息透過信令伺服器傳給 Bob。第四步,Bob 收到 offer 訊息後,呼叫 setRemoteDescription 方法將其儲存起來。第五步,Bob 呼叫 createAnswer 方法建立 answer 訊息, 同樣,answer 訊息中的內容是 Bob 的 SDP 資訊。第六步,Bob 呼叫 setLocalDescription 方法,將本端的 SDP 資訊儲存起來。第七步,Bob 將 anwser 訊息透過信令伺服器傳給 Amy。第八步,Amy 收到 anwser 訊息後,呼叫 setRemoteDescription 方法,將其儲存起來。

透過以上步驟就完成了通訊雙方媒體能力的交換。

上以就是信令伺服器應該處理的所有訊息,這些訊息組成了信令伺服器最基本的信令,每一個都必不可少,否則的話雙方就無法進行最終的通訊了。

在WebRTC 通訊時,光有信令是遠遠不夠的。因為 WebRTC真正要傳輸的是媒體資料,信令只不過是其中的一部分。在WebRTC中他會盡可能地透過P2P進行資料的傳輸,但在 P2P穿越不成功時怎麼辦呢?

搭建 STUN/TURN

在公網搭建一套 STUN/TURN 服務並不難。首先要有一臺雲主機,雲主機的話我就不做介紹了,大家去某個雲廠商購買就好了。

目前比較流行的 STUN/TURN 伺服器是 coturn 54,使用它搭建 STUN/TURN 服務非常的方便。

下面我們就來看一下它的基本步驟:

獲取 coturn 原始碼git clone https://github.com/coturn/coturn.git編譯安裝cd coturn ./configure --prefix=/usr/local/coturn sudo make -j 4 && make install配置 coturn網上有很多關於 coturn 的配置文章,搞得很複雜。大多數人都是從網上複製轉發的,其中有很多錯誤。其實只要使用 coturn 的預設設定就可以了,我這裡整理了一份,如下:listening-port=3478 #指定偵聽的埠 external-ip=39.105.185.198 #指定雲主機的公網IP地址 user=aaaaaa:bbbbbb #訪問 stun/turn服務的使用者名稱和密碼 realm=stun.xxx.cn #域名,這個一定要設定 所以,只需將上面 4 行配置項寫入到 /usr/local/coturn/etc/turnserver.conf 配置檔案中,你的 stun/turn 服務就配置好了。啟動 stun/turn 服務cd /usr/local/coturn/bin turnserver -c ../etc/turnserver.conf測試 stun/turn 服務開啟 trickle-ice 139 ,按裡面的要求輸入 stun/turn 地址、使用者和密碼後就可以探測stun/turn服務是否正常了。以我們的配置為例,輸入的資訊分別是:STUN or TURN URI 的值為: turn:stun.xxx.cn使用者名稱為: aaaaaa密碼為: bbbbbb測試的結果如下圖所示:從上圖我們可以看到該服務提供了 stun(srflx)和turn(relay)兩種服務。

STUN/TURN佈署好後,我們就可以使用它進行多媒體資料的傳輸了,再也不怕因為 NAT 和防火牆的原因導致雙方無法通訊的問題了。

小結

本文首先向大家詳細介紹了 WebRTC 三種類型信令訊息的控制與交換。然後給出了 STUN/TURN 伺服器的佈署、配置以及如何進行測試。

這裡需要特別強調的是,STUN/TURN的佈署雖然非常簡單,但像 WebRTC 一樣,其背後的原理卻很複雜。由於篇幅的原因,我這裡並沒有向大家做詳細的介紹,感興趣的同學可以將其做為了一切入點進行深入的研究。

17
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 人工錄入太慢了!教你一種高階的資料獲取技巧,不用學程式設計