WebRTC 前端实时通信技术

背景

随着Chrome、微软 Edge 和苹果 Safari 陆续宣布停止支持 Flash,Adobe 公司也正式宣布将在2020年年底停止对 Flash 的支持,这就使得国内大多数使用 Flash Player来支撑音视频等业务的公司面临着巨大的技术变革的考验。然而,在 Web 端技术不断向前发展,HTML5等标准逐渐成熟的大环境下,Web端开发者抛弃 Flash 来构建交互性更复杂的Web应用不再是一件困难的事情,反而会变得更加简单。

业务场景

目前,团队主要专注于直播、点播等视频相关的 P2P 业务上,客户端通过集成 SDK,能够获得更流畅播放体验并显著降低CDN分发成本,适用于互动直播、电视内容直播、赛事直播、在线视频、短视频等业务场景。支持 Android/iOS/OTT/Flash/HTML5 等系统平台,支持 arm/x86/mips 等架构。对于 HTML5 来说,团队要做的是应用WebRTC将已下载的音视频分片数据推送给订阅了该分片的对端用户,意在不影响用户播放体验的同时降低CDN的成本,同时拉开与竞品之间的距离,增大业务在价格方面的优势。

接下来,本文将从实战的角度来介绍如何使用 HTML5标准中 WebRTC相关 API 来实现 P2P 功能。

WebRTC

WebRTC(Web Real-Time Communications)是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC 包含的这些标准使用户在无需安装任何插件或者第三方软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。

纵观WebRTC建立P2P连接的过程主要是以下几步:

(1) 连接双方交换SDP(Session DescriptionProtocol,会话描述协议),用于描述“会话状态”,包含一系列的连接属性:要交换的媒体类型(音频、视频及应用数据)、网络传输协议、使用的编解码器及其设置、带宽及其他元数据;

(2) WebRTC内置了 ICE框架,负责候选项发现、连接检查、持久化等等,这部分工作对开发者是不可见的:开发者需要做的只是在初始化 RTCPeerConnection 对象时指定STUN 和 TURN 服务器;

(3) 若连接成功,最后就是 Peer 之间的数据分享过程了。

上述过程基本上就是进行实时通信需要经历的过程,整个过程说起来很简单,但实际上端与端之间通常存在有很多层的防火墙和 NAT 设备阻隔着,需要经过一系列繁琐的信令交换,网络地址转换、打洞等过程。幸运的是,WebRTC除了信令交换之外,其余的工作都已经帮我们实现好了,开发者可以将绝大多数的精力放在主要的业务逻辑上。

信令通道和会话协商

在建立连接和会话协商之前,我们需要一个信令(或信号)通道来交换信息,不幸的是,WebRTC 并没有为我们实现这部分的工作,而是将发送信号和协议的选择交给应用,无论是通过 HTTP、WebSocket还是其他任意的传递方式,只要能顺利到达对端即可。

在拥有了信令通道之后,就是会话协商的过程了,这个过程中交换的是会话描述协议信息,即 SDP 信息。当用户向对端用户发起 WebRTC 连接时,将创建一个称为提议的会话描述信息,该描述信息包含用户之间“对话”的配置信息,这有点像是在告诉对端用户:我将要去你家坐坐,你是不是得准备点茶点招待我啊?在对端用户收到提议方的会话描述信息后,将会回复一个应答的会话描述信息,告诉发起对话方:茶点准备好了,恭候您的大驾光临!

下述是具体的提议应答交换过程,如有 A 和 B 两个用户:

(1) A 调用 RTCPeerConnection.createOffer() 创建一个提议描述 SDP(A);

(2) A 调用 RTCPeerConnection.setLocalDescription() 设置得到的SDP(A) 信息;

(3) A 通过信令通道将SDP(A) 信息发送给 B;

(4) B 收到 A 的描述信息后调用RTCPeerConnection.setRemoteDescription() 记录对端用户的会话描述信息;

(5) B 调用RTCPeerConnection.createAnswer() 创建一个应答描述 SDP(B);

(6) B 调用RTCPeerConnection.setLocalDescription() 设置得到的 SDP(B) 信息;

(7) B 通过信令通道将SDP(B) 信息发送给 A;

(8) A 收到B 的描述信息后调用RTCPeerConnection.setRemoteDescription() 记录对端用户的会话描述信息;

ICE(Interactive Connectivity Establishment)

得到了对端用户的邀请确认后,双方此时就需要交换一下双方住址了,为了尽可能避免对方走错路错过了茶点最佳的品尝时间,双方都开始收集自己的详细地址信息,详细到走路怎么走,骑单车怎么走,打车又是怎么走,不得已时可能约上一个大家都熟知的地方相见。回到实际编码中来,要顺利的建立端到端的连接,两端之间必须能收发数据包,但通常端与端之间存在有很多层的防火墙和 NAT 设备阻隔着,需要经过一系列繁琐的网络地址转换、打洞等过程,总结来说这是一个寻找连接通道的过程,幸运的是,WebRTC 已经代替我们完成了这部分的工作。当需要连接的两端设置好本地和远端的会话描述后,本地 ICE 代理就会自动开始发现本地端所有可能的候选 IP 和端口的过程:

(1) 查询本地内网的 ip 地址;

(2) ICE 代理向 STUN 服务器查询,本地的外网 ip 和端口号;

(3) 如果端到端连接失败,数据将通过 TURN 服务器转发数据。

ICE 代理每发现一个新候选项就会自动回调 onicecandidate事件通知应用。此时,通过信令通道将该候选项 candidate 发送给对端 Peer,对端收到该候选项后则通过调用 RTCPeerConnection.addIceCandidate(candidate) 来增加端与端之间连接的通道方式,反之亦然。值得称赞的是,连接成功建立之后并不代表 ICE 代理的工作已经结束了,实际上此时 ICE 代理会继续收集本地候选项,意在找到一个更稳定的连接路径,这个过程对我们是不可见的。下图 ICE 代理的工作流程:

应用数据通道(DataChannel)

实际上 WebRTC 并不单单仅限于 Peer 之间分享音视频流,也支持任意应用数据交换(String,ArrayBuffer,Blob,File,Image等),而这仅仅只需要以下几步即可:

(1) 实例化一个 RTCPeerConnection 对象;

(2) 调用 RTCPeerConnection.createDataChannel(),实际上这一步只需在发起对话方创建即可;

(3) 接下来就是一系列的提议、应答和候选项通过信令通道交换的过程;

(4) 最终建立连接成功后,对端 Peer 会收到触发ondatachannel 的事件回调,其中事件中的 Event.channel 就是 Peer 间的数据通道,此时对话两端就可以通过这个“通道”来分享数据了。

初见 DataChannel 与 WebSocket 基本上是类似的,都支持 onopen、onmessage、onclose、onerror 事件回调,但两者之间仍然有一些区别,WebSocket 是在 TCP 的基础上构建的可靠有序的消息交付,而 DataChannel 是基于 UDP 的,当然也可以通过配置来指定是否有序和可靠性,提供了更多的灵活性配置,可自行搜索相关文章来了解。

现有 WebRTC 库

前文花了较多的篇幅来介绍 WebRTC 在建立端对端连接的相关过程,虽然没有贴出相关的代码,但相信大家在有了建连过程的基础后再自行搜索相关代码来看,会有事半功倍的效果!实际上,市面上已经有多家公司或组织已经封装了各自的 WebRTC 库,目前了解到的有:streamroot、webtorrent、peerjs、peer5等。

本文出现的初衷也正是为了了解这些库在实现 P2P 功能上有无独到之处,通过前文的描述我们知道,P2P 的核心要求就在于穿透 NAT 设备,只有穿越了它才能真正建立起端对端的连接,目前 NAT 设备有两种类型:对称型和锥型,而 P2P 需要的是锥型 NAT。从这些库对穿透这块的代码上来看并没有什么与众不同之处,更多的是在 STUN 无法穿透时配置了 TURN 来中转数据。但是十分幸运的是,根据 Google 提供的穿透数据来看:

  • 92%的时间可以直接连接(STUN)
  • 8%的时间要使用中继器(TURN)

在调研过程过程,也发现了一些比较有趣的网站,是基于 WebRTC 实现的在线视频通话和在线文字聊天 demo,有兴趣的可以在浏览器中打开一下的网站:

总结

在写这篇文章前花了一个星期来学习相关的知识包括: WebRTC API、NAT、信令服务、STUN 服务器、TURN 服务器等,但由于这部分的技术不是临时抱佛脚就能了解透彻的,是一个持续学习深入了解的过程。有点遗憾的是没在本文中介绍 NAT 的相关知识,实际上这部分内容可以单独拎出来讲解,等有空了再写一篇关于 NAT 的文章吧。

随着 Web 前端标准越来越成熟,浏览器能做到的东西越来越多,也许会逐渐替代客户端,这不得不说这很符合互联网的特点,相信有一天会出现一个标准,我们不再需要手机,不再需要安装软件,不再需要各种类型账号,实际上我们自身就是一个特定的 ID,将来所有的交互都是基于这个 ID 来提供不同的个性服务,无论我们走到哪都能得到所需的服务。想想都是满满的期待啊!

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

江天德的专栏

1 篇文章1 人订阅

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ThoughtWorks

GoCD的正确打开方式|洞见

事件:ThoughtWorks在2016年11月发布的技术雷达中将“Jenkins as a deployment pipeline”列为了“暂缓”。 Jenk...

4236
来自专栏小俊博客

Cloudreve1.0 – 随时随地,云端等你

1211
来自专栏FreeBuf

基于bro的计算机入侵取证实战分析

什么是计算机入侵取证 计算机取证是运用计算机及其相关科学和技术的原理和方法获取与计算机相关的证据以证明某个客观事实的过程。它包括计算机证据的确定、收集、保护、分...

3483
来自专栏顶级程序员

GitHub 上 10 款免费开源 Windows 工具

GitHub 是如今所有开源事物的中央仓库, 这个网站最近发布了一个叫做《2016 Octoverse 状态报告》,详细列出了从去年起其一系列亮点, 包括总的...

4258
来自专栏Android群英传

推送,从入门到放弃

802
来自专栏织云平台团队的专栏

织云Lite V1.4| 权限控制下的运营事故规避

随着业务发展,设备越来越多,各业务机器运行各自的功能程序,团队成员也在持续增加,开发、测试、运维等不同团队的同事各司其职。多团队合作模式带来的问题就是运营事故的...

1042
来自专栏程序人生 阅读快乐

Nginx模块开发指南:使用C++11和Boost程序库

Nginx 是由俄罗斯工程师Igor Sysoev 开发的一个高性能Web 服务器,运行效率远超传统的Apache、Tomcat,是世界第二大Web 服务器,被...

442
来自专栏数值分析与有限元编程

有限元分析软件ADINA

ADINA(Automatic Dynamic Incremental Nonlinear Analysis)软件是美国ADINA R&D公司的产品,是基于有限...

1001
来自专栏企鹅号快讯

Ruby 在缓慢衰落,缺少爆发点是关键;Google 明年关闭增强现实项目 Project Tango

参考:开源中国、solidot、cnBeta、腾讯科技等 0、Redmonk:Ruby 在缓慢衰落,缺少爆发点是关键 Redmonk 近日针对 Ruby 的发展...

1995
来自专栏Youngxj

关于旗下小杰网络论坛闭站说明

1294

扫码关注云+社区