最近研究了一下 WebRTC,写篇笔记记录下。
0. WebRTC 简介
WebRTC 是一种 p2p 技术,它可以在两个不同的浏览器之间建立直连,让它们互相传输数据、视频和音频流。
这个技术可以充分利用用户自己的上行带宽和网络环境,降低中心服务器的负载,既提升用户体验,又能降低服务提供者的成本。用在一些低成本的场景非常合适,比如视频会议、轻型联网游戏、内容共享网络等。
由于其低成本的优势,我想用它给 mywordle.org 升级,支持用户 1v1 对战。将来的话,还可以搞一些 FC 模拟器玩玩。
1. WebRTC 基本概念
WebRTC 的概念不少,初次连接也很复杂,有些我现在还没完全搞清楚。所以这个部分以后再慢慢更新。另外这里的内容并不是按着规范走的,而是来自我的实践。
1.1 基本概念
1.1.1 信令服务器
这可能是 WebRTC 里最重要的一个概念,每个浏览器 tab 页都是网络中的一个孤岛,必须通过信令服务器才能找到对方,建立连接。
信令服务器是必须的,不能通过人工方式完成两个节点的互联(或者说很难)。但是信令服务器并不一定要自己建,有不少公共的可以蹭。
1.1.2 Ice 服务器 RTCIceServer
同一个局域网内连接很简单,但实际上并不常见。我们日常使用的网络,无论移动网络还是家里的宽带,其实都是位于 NAT 后面,相当于总机分机的概念。两个 NAT 后面的应用想连接就比较困难了,此时就需要 RTCIceServer
帮忙,协商在两个 NAT 上打洞。
具体的实现逻辑我们不用关心,只要会用就行。目前有两类 RTCIceServer
:STUN 和 TURN。前者只负责给双方牵线搭桥,本身不介入连接,有很多公共服务可以蹭;TURN 不光能把两个端连接起来,还能在两端中间网络不通的时候作为 fallback 方案。功能更强,真正生产级别的产品都需要;但是相应的,TURN 需要更高的资源支撑,免费资源也很少。
1.2 发起连接
当用户 A 想要跟用户 B 建立 WebRTC 连接时:
- A 创建一个
RTCPeerConnectioin
对象 - 创建一个
offer
,其中包含着 A 的网络信息,其它人通过这个信息可能找到 A - A 把
offer
发给信令服务器 - 信令服务器把
offer
发给用户 B - 用户 B 记录下
offer
,然后生成answer
。answer
跟offer
其实是一样的,只是用来作为响应。这也是必须有信令服务器的原因。 - B 把
answer
发给信令服务器 - 信令服务器把
answer
发给 A - A 尝试用
answer
建立连接,如果是局域网,双方可能已经连上了 - 如果连不上,则 A 尝试通过 ice server 连接。
- A 创建自己的
icecandidate
信息,然后发给信令服务器 - 信令服务器将 A 的
icecandidate
发给 B - B 添加后,也创建自己的
icecandidate
,发给信令服务器 - 信令服务器将 B 的
icecandidate
发给 A - A 添加之,并尝试创建连接
- 如果一切正常,这个时候就连上了。
2. 实操
我建立了一个项目:meathill/webrtc-playground: learn webrtc (github.com),目前还在升级开发中。
- 实现一个 websocket 服务器(基于 socket.io),作为信令服务器,交换信令
- 用各种姿势尝试建立连接
- 同浏览器多 tab 连接成功
- 内网连接成功
- 手机开热点,尝试公网连接,也成功
- 尝试跟朋友连接,失败。遇到两个问题:
- 他家的网络是广州联通,我家是广州电信
- 他的手机网络是北京联通
- 目前的信令服务器会无条件广播各种信息,当我跟他都多开 tab 的时候,很难保证连接的两端是匹配的
- 于是接下来要重构。
3. 总结
这次学习过程一波三折。首先,WebRTC 的用户大部分关注音视频传输,毕竟这方面效果最明显;DataChannel 其实只算个添头,偏偏我最关注这个,所以找内容花了不少时间。
接下来,大部分范例代码都只是抄来抄去,一个 tab 内部来回连,经常会看错。另外,一些概念也不清不楚,比如 ice server,无法主动触发请求。
终于调通了内网和公网,又遇到联通电信问题……看来将来 TURN 服务器也必不可少。
欢迎吐槽,共同进步