webRTC 连接建立原理演示

713 阅读4分钟

本文同步发布在微信公众号nashaofu在路上,欢迎关注。

懒惰的人总是被世界推动着做事,在被动中遭受着“不得不”的折磨,在空虚中享受着自欺欺人的舒适。很久没有写东西了,人总是懒惰的,每次都是代码写完了,却不想写文章,总是害怕总结,觉得太麻烦了,花了几天时间才整理了一下代码,并写了这么点文字。​

本文主要讲述 webRTC 的建立过程,并包含了演示示例,在线预览地址https://nashaofu.github.io/webrtc-demo/,Github仓库源码为:github.com/nashaofu/we… 。并且本演示示例也入选了阮一峰老师的科技爱好者周刊(第 115 期)www.ruanyifeng.com/blog/2020/0…

本示例推荐clone仓库然后在本地运行,线上版本只能演示无服务器建立连接的页面。下面就以clone仓库的方式进行讲解。

1. 执行git clone github.com/nashaofu/we…

2. 进入项目文件夹,生成ssl证书相关文件(保证局域网能够正常访问)

mkdir ssl

cd ssl

openssl genrsa -des3 -passout pass:x -out server.pass.key 2048

# writing RSA key
openssl rsa -passin pass:x -in server.pass.key -out server.key

rm server.pass.key

openssl req -new -key server.key -out server.csr

openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt

3. 安装依赖并启动服务

# 安装依赖
yarn
# 启动服务
yarn start

4. 在浏览器中打开终端输出的地址,如遇到证书安全问题可参考https://blog.caojun.xyz/posts/macos_trust_ssl/

5. index.html是使用复制文本握手的示例,http.html是使用http建立连接的示例,socket.html是用来演示socket建立连接的示例,dataChannel.html是展示用webRTC传输文本内容的示例

webRTC 连接建立流程

image

交换offer和iceCandidata通常通过socket来交换,目的是方便对方网络情况变化后能够推送到参与会话的人,其实这个交换过程也可以用其他任何方式,只要能相互交换信息就可以。例如,A创建会话后,把自己的offer和iceCandidata通过邮件发送给B,B把这些信息设置到自己的会话中,然后把自己的answer和iceCandidata发送给A,只要在这期间网络状况没发生变化,就能够正常通话。关于webRTC,这篇文章(juejin.cn/post/684490…)讲得比较不错。MDN 上关于 webRTC 连接流程说明如下

image

下面主要讲一下index.html中手动拷贝方式建立连接的过程,只要理解了这个过程基本上就能理解其他方式。1. 进入页面选择创建会话

image

2. 复制生成的的信息给要邀请的人。这里生成的内容是createOffer生成的offer和icecandidate组成的对象,进行base64编码后的内容。

image

function tokenEncode(data) {
  // data为:{ offer: string, candidate: object[] }
  // candidata为:
  // {
  //    sdpMLineIndex: number,
  //    sdpMid: string,
  //    candidate: string
  // }
  return btoa(JSON.stringify(data))
}

3. 被邀请人打开网页选择加入会话,然后填写邀请人发送的信息到输入框,输入后点提交,会根据提交的内容解码出offer和icecandidate,然后会在图中2的区域生成answer和icecandidate的base64编码,把base64编码发送给邀请者

image

4. 邀请者收到answer和icecandidate的回执后,填写进回执内容输入框中,点提交,然后解码出answer和icecandidate。然后顺利的话就能进行视频通话了。

image

网络无法穿透问题

通常来说,如果我们仅仅靠上面的步骤只能实现局域网的P2P连接,不能穿透网关,具体原因主要是因为NAT 和防火墙,由于有这个原因存在,所以webRTC有STUN(Session Traversal Utilities for NAT)和TURN(Traversal Using Relays around NAT)两种类型的服务器,这两个主要是用在P2P连接不可用时作为中继服务器,所以使用中继服务器时,流量时候经过中继服务器的,不再是P2P的直接连接。所以在示例中,我有用到免费的中继服务器,以保证能联通网络。

  const pc = new RTCPeerConnection({
    iceServers: [ // 信令服务器列表
      {
        urls: 'stun:stun.l.google.com:19302'
      }
    ]
  })

webRTC 的应用

我们可以用webRTC搭建聊天室,也可用来做直播(白嫖流量)等等,我还看到过一个想法是用electron做的软件,在客户端里面也内置了webRTC的信令服务器(交换offer和icecandidate),所以如果安装的客户端足够多的话,我们也就能形成一个庞大的P2P网络了,可以做很多的事情。未来这种去中心化的东西也许还会有很大的潜力。

webRTC 建立连接交换offer和icecandidate的服务器通常叫做信令服务器。建立P2P网络的第一台服务器一般被叫做创世服务器,后面其他的客户端也同时会作为服务器接入网络。