WebRTC 入門教程(二)| WebRTC信令控制與STUN/TURN服務器搭建


WebRTC 入門教程(二)| WebRTC信令控制與STUN/TURN服務器搭建

作者:李超,音視頻技術專家。本文首發於 RTC 開發者社區,歡迎在社區留言與作者交流。 https://webrtc.org.cn/webrtc-tutorial-2-signaling-stun-turn/

本文將向大家介紹兩個方面的知識:

  • WebRTC信令控制
  • STUN/TURN服務器的搭建

前面的文章中已經向大家介紹了如何構建信令服務器。但構建的信令服務器是如何工作的?那些消息需要信令服務器控制和中轉?這些此前並沒有做詳細的說明,而本文將對這些問題做詳細的討論。

另一方面,在真實的網絡中,WebRTC是如何進行NAT穿越的呢?如果穿越不成功,我們又該如何保證用戶服務的呢?這些知識也將在本文中給出答案。

信令

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

信令服務器用於交換三種類型的信息:

  • 會話控制消息:初始化/關閉,各種業務邏輯消息以及錯誤報告。
  • 網絡相關:外部可以識別的IP地址和端口。
  • 媒體能力:客戶端能控制的編解碼器、分辯率,以及它想與誰通訊。

下面我們就來詳細討論一下這三類消息:

會話控制消息

會話控制消息比較簡單,像房間的創建與銷毀、加入房間、離開房間、開啟音頻/關閉音頻、開啟視頻/關閉視頻等等這些都是會話控制消息。

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

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

  1. ...
  2. socket.on('create or join', function(room) {
  3. var clientsInRoom = io.sockets.adapter.rooms[room];
  4. var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
  5. if (numClients === 0) {
  6. socket.join(room);
  7. logger.debug('Client ID ' + socket.id + ' created room ' + room);
  8. socket.emit('created', room, socket.id);
  9. } else if (numClients === 1) {
  10. io.sockets.in(room).emit('join', room);
  11. socket.join(room);
  12. socket.emit('joined', room, socket.id);
  13. io.sockets.in(room).emit('ready');
  14. } else { // max two clients
  15. socket.emit('full', room);
  16. }
  17. });
  18. ...

 

該代碼的邏輯非常簡單,當收到 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 時,為了保證雙方可以正常通訊,此時只能通過服務器中轉來保證服務質量了。

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

在 WebRTC 信令服務器端,收到網絡消息信令,即 message 消息時,不做任何處理,直接轉發。代碼如下:

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

客戶端接收到 message 消息后,會做進一步判斷。如果消息類型為 candidate,即 網絡消息信令時,會生成 RTCIceCandidate 對象,並將其添加到 RTCPeerConnection 對象中,從而使 WebRTC 在底層自動建立連接。 其代碼如下:

  1. socket.on('message', function(message) {
  2. ...
  3. } else if (message.type === 'candidate') {
  4. var candidate = new RTCIceCandidate({
  5. sdpMLineIndex: message.label,
  6. candidate: message.candidate
  7. });
  8. pc.addIceCandidate(candidate);
  9. } else if (...) {
  10. ...
  11. }
  12. });

 

交換媒體能力消息

在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,使用它搭建 STUN/TURN 服務非常的方便。

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

  • 獲取 coturn 源碼
    1. git clone https://github.com/coturn/coturn.git
  • 編譯安裝
  1. cd coturn
  2. ./configure --prefix=/usr/local/coturn
  3. sudo make -j 4 && make install

 

  • 配置 coturn

網上有很多關於 coturn 的配置文章,搞的很復雜。大多數人都是從網上拷貝轉發的,其中有很多錯誤。其實只要使用 coturn 的默認設置就可以了,我這里整理了一份,如下:

  1. listening-port=3478 #指定偵聽的端口
  2. external-ip=39.105.185.198 #指定雲主機的公網IP地址
  3. user=aaaaaa:bbbbbb #訪問 stun/turn服務的用戶名和密碼
  4. realm=stun.xxx.cn #域名,這個一定要設置

所以,只需將上面 4 行配置項寫入到 /usr/local/coturn/etc/turnserver.conf 配置文件中,你的 stun/turn 服務就配置好了。

  • 啟動 stun/turn 服務
  1. cd /usr/local/coturn/bin
  2. turnserver -c ../etc/turnserver.conf

 

  • 測試 stun/turn 服務

打開 trickle-ice ,按里面的要求輸入 stun/turn 地址、用戶和密碼后就可以探測stun/turn服務是否正常了。

以我們的配置為例,輸入的信息分別是:

  1. STUN or TURN URI 的值為: turn:stun.xxx.cn
  2. 用戶名為: aaaaaa
  3. 密碼為: bbbbbb

測試的結果如下圖所示:

從上圖我們可以看到該服務提供了 stun(srflx)和turn(relay)兩種服務。

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

小結

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

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM