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

做者:李超,文章首發於 RTC 開發者社區,如遇到相關問題,能夠點擊這裏與做者直接交流。git

前言

本文將向你們介紹兩個方面的知識:github

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

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

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

信令

WebRTC 信令控制的架構圖以下所示:服務器

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

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

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

會話控制消息

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

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

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

...

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 時,爲了保證雙方能夠正常通信,此時只能經過服務器中轉來保證服務質量了。

因此 中繼候選者的優先級是最低的,只有上述兩種候選者都沒法進行鏈接時,纔會使用它。

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

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,使用它搭建 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 ,按裏面的要求輸入 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 同樣,其背後的原理確很複雜。因爲篇幅的緣由,我這裏並無向你們作詳細的介紹,感興趣的同窗能夠將其作爲了一切入點進行深刻的研究。

相關文章
相關標籤/搜索