本文引用自Hussein Nasser的两个视频分享,原文内容由卢冰聪翻译整理,即时通讯网收录时有大量修订和重新排版。
本文主要分享了WebRTC的基本概念、关键技术术语(包括NAT、STUN、TURN、ICE、SDP 和信令),着重讲解了WebRTC是如何实现P2P通信以及WebRTC信令的作用,同时讨论了WebRTC在技术上的优势和劣势,最后还提供了一个简单的WebRTC Demo代码。
- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》- 开源IM框架源码:(备用地址点此)
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。
(本节内容引用自《实时音视频入门学习:开源工程WebRTC的技术原理和使用浅析》一文)
建立它的理由是人们需要用一种标准的、低延迟的方式来传递媒体数据(视频&音频)。
所谓“标准的”意味着我们需要简单易使用的 API。而所谓“低延迟的”意味着需要一种合适的协议,UDP 显然是一个好的选择,因为 UDP 没有过多的应答过程(Acknowledgment)。但我们需要的协议要比 UDP 更好,要能支持 P2P 的通信。因为一旦依赖服务器来传递内容就会因为反向代理或者穿透引入额外的延迟,用户需要进行终止、观察、处理、转化流等操作,这些都会造成额外消耗。对于视频传输、特别是直播、会话等场景,用户希望内容到达得越快越好,所以 P2P 是最快的路径。
此外,WebRTC 也旨在实现浏览器之间丰富的沟通。浏览器已经发展了很长时间,它“拥有”大量的优质资源,它可以访问摄像头和麦克风,这些特性都值得被开发利用。用户不需要写自己的应用,而是基于 WebRTC 的标准 API 便可以轻松使用。不仅是浏览器,在移动设备和 IoT 设备通信时也同样。
举个例子:A 想要与 B 进行通信,但 A 与 B 之间“互不相识”。所以 A 首先需要找到所有 Public(不是 B)能连接到它的途径,检查 A 是否有一个公共 IP 能被 Public 识别或使用,如果没有检查 A 的路由器是否允许公开端口转发规则、是否在路由上有公共代表等等。B 也做了以上同样的事。
此外:A 和 B 还会收集自身所支持的加密方式、安全参数、视频编解码器等等大量的信息,注意这些信息还没有被送到对端,在这个阶段只是广泛地收集。所有这些信息,构成了“SDP”。
这种工作方式表面上是有些“愚蠢的”,部分人可能会认为“既然我已经有了 A 和 B 之间通信的线路,那还要 WebRTC 做什么呢?”但认真思考一下就可以发现,WebRTC 只要首次通信双方交换了 SDP,后面就会实现线P 通信,不再需要 WhatsApp、QR 等等中间途径,不会有比这更快的通信路径。因此最终 A 通过最优路径连接到了 B,这就是 WebRTC 的工作流程。
如上图所示:假设 A 找到了 A1、A2、A3 三种方式可以访问它,同时还找到了安全参数、媒体选项等信息。同时,B 也做了一样的工作。接下来,他们通过一些方式(例如 WhatsApp)交换了以上信息。然后 A 找到 B2 是可用的最佳路径,而 B 也发现 A1 是可用的最佳路径,那么二者将通过这条路径直接连接彼此。
接下来我们将对 WebRTC 的各项关键技术和概念进行初始理解,对细节内容进行讲述。
首先我们来了解 NAT 的细节(学习 WebRTC 是如何进行正确的网络地址转换),其次了解为什么我们需要 STUN 和 TURN,此外还会介绍 ICE、SDP 以及信令交换的相关内容。
如果你有一个公开的 Public IP 地址,连接过程将不会有什么问题。因为你会像 Web 服务器一样一直监听端口,把端口和 IP 都提供给对方后,你和它就可以直接进行连接了。但在大多数情况下,用户都是隐藏在公共网络之后的,无法直接连接。
首先:你的机器会构建一个数据包,声明想向 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 表查询对应地址完成通信(如下图所示)。
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 端口进行的通信。
在默认情况下:WebRTC 可以支持前三种 NAT 方式,对最后一种并不友好。实际上 90% 以上的通信就是通过前三种方式完成的,最后一种作者个人认为没有使用的价值。
《P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解(基本原理篇)》
《P2P技术详解(三):P2P中的NAT穿越(打洞)方案详解(进阶分析篇)》
STUN 是非常轻量级的,用户可以使用 docker 建立一个 STUN 服务器。
STUN 服务器的目的就是让用户找到自己的 Public 表示,并通过这个 Public 表示与其他用户进行通信。如果我们使用的是像大约 1996 年或 2000 年早期时那样的 Public IP 地址,通信也将非常简单。但就现在而言,我们必须使用 STUN 服务器。
首先创建一个数据包进行 STUN 请求:STUN 服务器的地址为 9.9.9.9:3478,同样在路由器创建了 NAT 表并进行了地址转换,然后数据包被送到了 STUN 服务器。
服务器收到请求后:为 10.0.0.2 的机器构建了一个 Public 表示 5.5.5.5:3333,并把这个信息打包进一个数据包进行反馈。
值得注意的是:这二者之前并没有进行过通信。如果是 Full-cone NAT,那么没有问题可以连接。如果是 Address restricted NAT,第一个请求连接的请求将会失败。在这种情况下,用户需要通过服务器建立至少一个通信请求,先让两个地址都能保存在两端的路由器中,这样再次通过 Public 表示进行连接请求时就能找到匹配的地址,继而可以完成连接。Port restricted NAT 工作原理与之类似。
所有的通信内容都要经过 TURN 服务器的转发,所以 TURN 服务器的维护成本比较高,这也是为什么几乎没有人免费提供这种服务器供用户使用。
下图是一个 TURN 服务器工作流程的示例,二者之间并不是直接的 P2P 通信,所有的信息都经过了 TURN 服务器进行转发。
这里有一个开源库也可以帮助大家创建属于自己的 TURN 服务器,地址是:。
在建立了很多 STUN 和 TURN 服务器后,从 A 到 B 之间的路径有了非常多的选择,为了更好的处理这些路径,人们提出了 ICE。
ICE 会收集所有可用的通信路径作为“候选人”(ICE Candidates),有可能是本地 IP 地址、STUN 和 TURN 服务器提供的地址等等。收集到的所有地址都将放入 SDP 中,再送到对端,对端通过解析 SDP 来了解我方提供的重要信息。
最后:如果想更多地了解STUN、TURN、ICE,可以阅读:《P2P技术详解(四):P2P技术之STUN、TURN、ICE详解》。
SDP 是一种用于表述 ICE Candidates 的格式,它描述了网络选项、媒体选项、安全选项和其他很多信息,开发者甚至可以自定义 SDP 内容。
实际上 SDP 并不是一种协议,只是一种数据格式,但 SDP 是 WebRTC 中最重要的几个概念之一。它的设计目的是将用户产生的 SDP 送至其他端,送的方式并不关心。
Signaling 过程是将用户产生的 SDP 通过某种方式传递给想要通信的那方。
如上所述,以何种方式传递并不重要。很多人通过WebSocket 或者 socket.io来传递 SDP 信息,这个过程就是 Signal SDP。
尽管要找到所有的 ICE candidate 是耗费时间的,但一旦完成了这个过程,下一步就是创建一个 SDP,进而生成一个 QR code 并把 QR code 公布到 twitter 上,其他人扫描了这个二维码就可以获取相应的 SDP。
这个过程是通过 twitter、QR code、Whatsapp、WebSockets、还是 HTTP 请求都不重要,因为实际上就是将一个长字符串传递给其他人罢了。
信令是配置、控制、以及结束用户间通信会话的过程。端到端通信(即P2P)需要信令来建立。
在连接阶段,用户使用信令服务器间接通信建立连接,在连接建立结束后,两用户直接通过音视频信道通信。
可以看到两个用户希望建立 WebRTC 连接,两端直接建立连接前都可以连接到同一个信令服务器,并通过该服务器交换 SDP 信息。在 SDP 请求和答复交换结束后,两用户都可以获取各自的 IP 地址和音视频配置等信息。之后就需要用 TURN 或者 STUN 服务器来穿透 NAT,达到用户间的直接 WebRTC 连接。
P2P 通信是非常棒的:对于高带宽内容可以有降低的延迟。P2P 是最快的路径,不需要经过其他的第三方进行通信。即使通互联网传输要经过大量的路由器,但如果内容已经被加密了所有的路由器都不会查看内容,它们会直接传递数据包,所以 P2P 是非常好的通信方式。对于高带宽内容,它们通过 UDP 直接被“送入”和“推出”,通过 P2P UDP 传递这些内容(特别是视频内容),用户将收获最好的性能。2)
标准可用的 API:WebRTC 有一套非常标准、非常优雅的 API,可以直接在浏览器中应用,不需要安装其他的包、也不需要用多余的开发工具。7.2缺点
需要维护 STUN 和 TURN 服务器:在某些情况下 P2P 不能工作,你仍需要一个 TURN 服务器。但维护 STUN 和 TURN 服务器需要耗费大量的人力物力,特别是 TURN 服务器。因为你首先要花钱维护一个 Public IP,并且必须维护这个服务器使其可以正常启动和运行。作者个人认为与其花费这种代价,不如自己建立一个拥有全部控制权的服务器,进行反向代理。2)
在参与者过多的情况下P2P 会崩溃:假设有 100 个人想要相互交流,你会创建 P2P 连接吗?那会是几百乘几百的连接量,因为每个人都需要连接到其他任何一个用户,这将是非常大规模的。但如果你有一个集中式服务器,每个用户只需要和这个服务器建立一个连接,你可以通过这个服务器控制所有的流量,这明显是一种更好的方式。所以 WebRTC 有时候无法用在游戏上,你没办法利用 WebRTC 来创建一个多用户游戏,当然 3 个用户是可以的,但几百个用户作者认为是无法实现的。8、WebSocket 和 WebRTC 的区别