本文引用自Hussein Nasser的两个视频分享,原文内容由卢冰聪翻译整理,即时通讯网收录时有大量修订和重新排版。
1、内容概述
本文是专为学习开源实时音视频工程WebRTC的入门者编写的速成指南。
本文主要分享了WebRTC的基本概念、关键技术术语(包括NAT、STUN、TURN、ICE、SDP 和信令),着重讲解了WebRTC是如何实现P2P通信以及WebRTC信令的作用,同时讨论了WebRTC在技术上的优势和劣势,最后还提供了一个简单的WebRTC Demo代码。
(本文已同步发布于:http://www.52im.net/thread-4184-1-1.html)
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穿越(打洞)方案详解(进阶分析篇)》
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 其实也使用了 WebSocket
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、参考资料
[4] 良心分享:WebRTC 零基础开发者教程(中文)[附件下载]
[6] 新手入门:到底什么是WebRTC服务器,以及它是如何联接通话的?
[8] 开源实时音视频技术WebRTC在Windows下的简明编译教程
[9] 零基础入门:基于开源WebRTC,从0到1实现实时音视频聊天功能
[10] 实时音视频入门学习:开源工程WebRTC的技术原理和使用浅析
[12] 搞懂现代Web端即时通讯技术一文就够:WebSocket、socket.io、SSE
[13] NAT详解——详细原理、P2P简介
(本文已同步发布于:http://www.52im.net/thread-4184-1-1.html)
网友评论