引言

WebRTC的全称是Web Real-Time Communication,Web实时通讯。这个API可以让浏览器与服务器甚至两个浏览器之间建立实时通信信道。WebRTC允许两个浏览器不经过服务器互相传输数据,因此WebRTC可以轻松做到低延迟与高可用。本文将简单介绍这个强大的API。
实时通讯大家应该都不陌生,从QQ到直播弹幕到在线网络游戏,都有实时通讯技术的身影。大家都用过的peer to peer(p2p)模式的产品,比如bt下载,电驴下载。这些应用通常都需要安装独立客户端,有时需要更新才可以使用。但是你有没有想过在浏览器中也可以做到这两点,这就引出了本文的主角————Web Real-Time Communication(WebRTC)。本文将用简单易懂的语言介绍这个强大的API。

1. 什么是WebRTC

WebRTC的全称是Web Real-Time Communication,Web实时通讯。这个API可以让浏览器与服务器甚至两个浏览器之间建立实时通信信道。WebRTC允许两个浏览器不经过服务器互相传输数据,因此WebRTC可以轻松做到低延迟与高可用。本文将简单介绍这个强大的API。
WebRTC Logo

举几个WebRTC的经典使用场景的例子:腾讯课堂利用WebRTC实现课堂视频的推送与播放,聊天区的消息发送与推送;远程会议使用WebRTC实现视频双向传输。或许你有疑惑,就这?其他技术就不能实现这些功能?网页实时通信依赖各种标准,大部分标准并没有把即时通信纳入考量范围,所以即时通讯API的选择相对有限。诚然,Flash确实可以很好地实现上面所说的功能,但是Flash效率低下,在2020年Flash早已停止更新,浏览器也开始逐渐屏蔽Flash。WebRTC API被纳入W3C标准,目前主流的浏览器均支持该API,所以网页实时通讯以及p2p的重任就落在WebRTC身上。

2. WebRTC历史

2010年5月,Google以6820万美元收购VoIP软件开发商Global IP Solutions的GIPS引擎,并改为名为“WebRTC”。
WebRTC使用GIPS引擎,实现了基于网页的视频会议,并支持722,PCM,ILBC,ISAC等编码,同时使用谷歌自家的VP8视频解码器;同时支持RTP/SRTP传输等。
2012年1月,谷歌已经把这款软件集成到Chrome浏览器中。同时FreeSWITCH项目宣称支持iSAC audio codec。
现在WebRTC已经几乎被所有主流浏览器兼容。

3. WebRTC基本概念

candidate

candidate描述了自己的 网络类型 地址等一些用于互联的参数

简单来说 candidate包装用于两端建立连接的信息,让两端可以互相知道对方的网络信息以及webrtc配置。下面是一个常见的candidate。

candidate: "candidate:2353526612 1 udp 2122260223 192.168.6.2 51053 typ host generation 0 ufrag Q4Ir network-id 2",

Session(会话)

Session(会话)是WebRTC中重要的概念,打个比方,我跟小明打电话,我们之间就是建立了会话。在WebRTC中,会话就是两端建立连接并且能互相传递信息的基础。

Sdp(会话描述)

Sdp的全称是SessionDescription,相信看名字就知道Sdp是什么作用了。
具体一点讲,Sdp包装了会话的所有信息
下面是一个真实的sdp数据,不需要过于关注细节。数据仅用于展示Sdp的作用,本文与这个数据关系并不大。(/doge)

  1. 安全描述:秘钥交换,让WebRTC连接可以在加密的环境下进行,提高了安全性。
  2. 流媒体描述:描述了自己的视频音频等数据的信息,比如编码
  3. 网络信息
  4. 服务质量:简单来说就是初步检测网络卡不卡
v=0
o=- 7678841878411856999 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=msid-semantic: WMS 57ec53c9-a162-4022-a88b-5280a8670166
m=video 9 UDP/TLS/RTP/SAVPF 96 97 125 107 114 115 116
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:hFeI
a=ice-pwd:r9YLgLYvZjA9NmNQ6P9cuzmP
a=ice-options:trickle
a=fingerprint:sha-256 9E:7D:5C:7E:35:0E:3A:CF:4E:E6:13:F9:8E:E5:A9:18:8B:37:C6:38:ED:25:B4:59:D7:F6:D6:3C:38:AE:17:3D
a=setup:active
a=mid:0
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:13 urn:3gpp:video-orientation
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:8 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07
a=extmap:9 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendrecv
a=msid:57ec53c9-a162-4022-a88b-5280a8670166 d719b4cb-27e5-4e7f-a548-ca9c96c141a0
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:125 H264/90000
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 transport-cc
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=125
a=rtpmap:114 red/90000
a=rtpmap:115 rtx/90000
a=fmtp:115 apt=114
a=rtpmap:116 ulpfec/90000
a=ssrc-group:FID 3521319142 925057533
a=ssrc:3521319142 cname:5uGqECGiizeRCDiO
a=ssrc:925057533 cname:5uGqECGiizeRCDiO

Offer(发起(者))

继续打个比方,我给小明打了个电话,我就是发起者。因为WebRTC的相当一部分技术是来自一家voip厂商,所以这里面也少不了传统电话的影子,这个概念也成为了我初学WebRTC时的一个障碍。

Answer(接受(者))

Offer一样,小明接到了我的电话,他是是接受者。在WebRTC会话建立的时候,两端需要对号入座,一个人作为发起者另一个人作为接受者。

signal(信令)

信令是candidateSdp的载体。
这么说可能很难理解信令是什么,想象一个场景,我准备邮寄一本书给远方朋友,但是我只有这个朋友的住址,这就意味着我不能直接通知他过来拿书。这时我需要把书包装好贴上快递单,把快递当做传书的载体,交给快递员,通过寄快递的方式把书送到他手上。
回看WebRTC的信令就很类似这个快递包裹,浏览器把对方的识别码(类似qq号码,微信号)和要发送的candidateSdp打包然后”邮寄”给对方。

信令服务器

信令服务器相当于”快递公司”。
两台机器互相不知道对方的时候,就需要一个信令服务器信令准确无误地传给接受者。

4. 会话是如何建立的?

先假设有两台接入互联网的电脑,一台电脑放在上海,另一台电脑放在广州。我在广州而小明在上海,我们互相知道对方的”号码”,而且我们与信令服务器的连接畅通无阻。我发起了一个通话。

这两台机器建立会话之前,浏览器不知道对方的ip地址。

  1. 我发起通话,建立了一个会话A,并且把自己加入会话A
  2. 我把candidateSdp以及小明的”号码”发送给信令服务器
  3. 信令服务器拿到我的信令,准确无误地把这个信令发给了小明
  4. 小明收到了我的candidateSdp,创建并加入了一个会话B。并且根据我的Sdp把我也加入会话B
  5. 小明candidateSdp以及我的”号码”发送给信令服务器
  6. 信令服务器拿到小明的信令,准确无误地把这个信令发给了我
  7. 我收到了小明的candidateSdp,根据小明的Sdp把小明也加入会话A
  8. 此时,会话建立成功了,即使信令服务器突然关机,我与小明也可以继续通话。

简化的WebRTC连接建立时序图

要注意的是,这里所说的流程是简化版,在实际的WebRTC会话建立过程中,信令交换是频繁的。candidate的交换往往会发生多次。

5. 互联的秘密—NAT与打洞

5.1 NAT技术

关于NAT

NAT英文全称是“Network Address Translation”,中文意思是“网络地址转换”,它是一个IETF(Internet Engineering Task Force, Internet工程任务组)标准,允许一个整体机构以一个公用IP(Internet Protocol)地址出现在Internet上。顾名思义,它是一种把内部私有网络地址(IP地址)翻译成合法网络IP地址的技术,如下图所示。因此我们可以认为,NAT在一定程度上,能够有效的解决公网地址不足的问题。

用一个简单的例子来理解NAT。每个ip地址有65536个端口,NAT可以理解为一个端口调度员。
比如运营商给路由器分配了一个可以被公网访问的ipv4地址1.2.3.4,路由器给家中的设备分配了192.168.1.x的地址。
在上网的过程中,假设设备A使用了192.168.1.2:50000(ip地址为192.168.1.2,端口为50000),路由器把192.168.1.2:50000映射到1.2.3.4:56666,设备B使用了192.168.1.3:50000,路由器把192.168.1.3:50000映射到1.2.3.4:56667
这个时候服务器与1.2.3.4:56667通讯,路由器会转发给设备B,服务器与1.2.3.4:56666通讯,路由器会转发给A。
这样就实现了使用一个ip让多台设备同时连接互联网。

NAT带来的好处

首先是增加了ipv4承载的设备数量。ipv4的IP地址只有32位,实际可用地址大约只有30多亿个。就在2019年,ipv4已经被完全分配完毕,这就意味着已经没有更多ipv4地址。NAT的作用是网络地址转换,可以让多台设备共享一个ip连接互联网,这就让30多亿个ipv4地址可以支撑远高于30多亿台设备。
其次是让网络更加安全,因为存在内网到公网的映射,使得计算机只有较少数量的端口可以被公网访问,降低了被攻击的可能性。如果一台机器拥有一个公网ip,而且没有开启防火墙。这就意味着这台机器65535个端口都可以被公网访问,假设445端口的smb服务出现漏洞,攻击者可以直接利用445端口攻击设备。但是有了NAT的存在,445端口默认不会被映射到公网,只有局域网设备可以访问,攻击难度倍增。

NAT带来的坏处

NAT带来的坏处也很明显,ip与设备不再是一对一的关系,而是一对多的关系,当公网的一台设备A想准确地访问一台在不同局域网的设备B时,就算知道了设备B的公网ip地址,设备A也无从下手,因为它不知道设备B的公网ip地址1.2.3.4的哪个端口被映射到设备B。因为NAT阻止了两台设备相互连接,所以WebRTC之类的p2p连接就无法建立。

NAT类型

NAT类型检测

NAT是一种从内网ip到公网ip的映射关系,其中映射的规则可以被分为四个类型,这就叫做NAT类型。如果你拥有PS4游戏机,在网络设置中可以查看当前网络的NAT类型。Windows系统的电脑也可以安装”NAT类型检测”软件实现网络NAT类型的查看。

NAT两大类型

NAT一共有四种类型,两大类型:锥形NAT与对称NAT,其中123类型都属于锥形NAT,只不过随着序号的增大安全策略更加严格。4属于对称NAT。
有一个实际例子:
NAT例子
NAT例子

1. Full Cone(全锥形)

全锥形就是没有任何限制的锥形

2. Restricted Cone(IP受限锥型)

引入了一个限制,只转发主动连接过的ip发来的包。
举例:
基于图1情景,设备A服务器1交换过数据,但是从来未与服务器2交换过数据。此时服务器2连接1.2.3.4:56666,路由器拒绝转发来自服务器2的所有包。

3. Port Restricted Cone(PORT受限锥型)

在Restricted Cone(IP受限锥型)的基础上再引入端口限制。
举例:
基于图1情景,假设设备A只与服务器1的10000端口交换过数据,此时服务器1使用10001端口向1.2.3.4:56666发送数据,路由器拒绝转发来自服务器1 10001端口的包。

4. Symmetric(对称型)

对称型如上文图2所示,NAT前的端口号与NAT后的端口号是一对多的关系,而且每个映射都遵循Port Restricted Cone(PORT受限锥型)的规则。

5.2 打洞—突破NAT互联

关于打洞

打洞的原理很简单,设备A与一台服务器建立连接,此时路由器会建立一个NAT映射,接着记录设备A的NAT信息(比如NAT前的IP地址和端口,NAT后的IP地址和端口)。有了这些信息,其他机器就可以准确地从NAT后的IP地址和端口访问设备A

打洞协议:STUN和TURN

打洞协议STUN的作用是让处于NAT里的设备获取自己NAT后的可以被公网访问的IP和端口号,以及NAT类型。
TURN是中继穿透NAT,顾名思义,TURN充当了两方通信的中继,所以数据会全部经过TURN服务器。

简单理解STUN的实现方式

上面说到打洞过程,因为设备A只能获取到NAT的ip与端口号,而服务器可以获取到设备ANAT的ip与端口号,所以服务器把获取到的信息返回给设备A设备A自然可以获取到自己NAT后的IP与端口

6. 信令服务器

信令服务器有两个作用,一是交换网络环境信息,二是交换会话信息。
信令服务器的实现多种多样,常见的解决方案是WebSocket或者HTTP长连接。

6.1 交换网络环境信息

了解了NAT与打洞后,再着眼于前文的candidatecandidate实际上携带了自己NAT前后的ip与端口信息,这里称为网络环境信息。设备A把自己NAT前后的ip与端口信息通过信令服务器发送给设备B设备B可以直接与设备ANAT后的ip与端口建立连接,从而实现设备A设备B的直接连接。当然,设备B也会将自己的网络环境信息发送给设备A,即使一方的网络环境无法建立直接连接,另一方合适的网络环境也可以让这次连接顺利进行。

6.2 交换会话信息

Sdp(会话描述)包含了会话的基本信息,Sdp(会话描述)通过信令服务器发送给另一端,使另一端可以顺利初始化会话。

结语

读完这篇文章相信你对WebRTC也有一些初步的认识,WebRTC是多项技术的集合体,需要掌握多方面的知识才能发挥出它的强大之处。如果让我把WebRTC分成几个主要部分,我认为WebRTC可以分为连接部分与多媒体部分,本文主要介绍了WebRTC的基本概念以及连接部分,如果你也对有无限可能性的Web实时通讯感兴趣,可以关注我的博客,WebRTC旅程刚刚开始。

预告:

  1. WebRTC多媒体介绍
  2. WebRTC实践:动手写一个视频通话网站
  3. WebRTC dataChannel妙用
  4. WebRTC实践:写一个远程快传网站