WebRTC 入门教程(二)| WebRTC信令控制与STUN/TURN服务器搭建

WebRTC 入门教程(二)| WebRTC信令控制与STUN/TURN服务器搭建

做者:李超,音视频技术专家。本文首发于 RTC 开发者社区,欢迎在社区留言与做者交流。 https://webrtc.org.cn/webrtc-tutorial-2-signaling-stun-turn/git

本文将向你们介绍两个方面的知识:github

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

前面的文章中已经向你们介绍了如何构建信令服务器。但构建的信令服务器是如何工做的?那些消息须要信令服务器控制和中转?这些此前并无作详细的说明,而本文将对这些问题作详细的讨论。web

另外一方面,在真实的网络中,WebRTC是如何进行NAT穿越的呢?若是穿越不成功,咱们又该如何保证用户服务的呢?这些知识也将在本文中给出答案。服务器

信令

WebRTC 信令控制的架构图以下所示:网络

信令服务器用于交换三种类型的信息:架构

  • 会话控制消息:初始化/关闭,各类业务逻辑消息以及错误报告。
  • 网络相关:外部能够识别的IP地址和端口。
  • 媒体能力:客户端能控制的编解码器、分辩率,以及它想与谁通信。

下面咱们就来详细讨论一下这三类消息:app

会话控制消息

会话控制消息比较简单,像房间的建立与销毁、加入房间、离开房间、开启音频/关闭音频、开启视频/关闭视频等等这些都是会话控制消息。socket

对于一个真正商业的WebRTC信令服务器,还有许多的会话控制消息。像获取房间人数、静音/取消静音、切换主讲人、视频轮询、白板中的画笔、各类图型等等。但相对来讲都是一引发比较简单的消息。ide

在咱们以前的例子中,服务端只处理了一个会话消息 create or join,即房间的建立与加入消息。代码以下:post

  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 同样,其背后的原理确很复杂。因为篇幅的缘由,我这里并无向你们作详细的介绍,感兴趣的同窗能够将其作为了一切入点进行深刻的研究。

相关文章
相关标签/搜索