
webrtc 的点对点连接穿透方案设计
说实话,第一次接触 webrtc 的时候,我总觉得"穿透"这个词挺玄乎的。后来做项目多了才发现,这东西说白了就是解决一个很朴素的问题:怎么让两个人在不同的网络环境下能顺顺当当地说上话。这篇文章我想用一种更接地气的方式,聊聊 WebRTC 穿透方案到底是怎么回事,以及在实际应用中需要注意哪些细节。
先搞明白:为什么需要"穿透"
在理想状态下,两台电脑想通讯,直接知道对方的 IP 地址和端口就能握手了。但现实世界远比这复杂得多。我们现在用的家庭宽带、公司网络,基本上都处在 NAT(网络地址转换)后面。什么意思呢?你家的路由器只有一个公网 IP 地址,但里面连着手机、电脑、平板好几个设备。路由器会给每个内网设备分配一个私有 IP,比如 192.168.x.x 这种。当你访问外网的时候,路由器帮你把请求"伪装"成从公网 IP 发出去的,对方看到的就是路由器的公网 IP,而不是你电脑的私有 IP。
这样做有好处,节省了公网 IP 资源,也安全些,毕竟外网看不到你内网设备的真实 IP。但问题来了:如果别人想主动联系你,他只知道你路由器的公网 IP,根本不知道你内网电脑的具体地址。就像你想给一栋写字楼里的人寄快递,写字楼有一个统一的收发室,你只知道收发室的地址,却不知道具体哪个工位,这快递怎么送得到?
这就是 WebRTC 面临的首要挑战。除了 NAT,还有防火墙这道坎。有些公司出于安全考虑,会限制外网主动访问内网的请求。或者某些网络环境特别激进,直接把所有非主动发起的连接都拦截了。所以穿透方案要解决的问题就是:让两个在不同 NAT 后面的人,能够找到彼此,成功建立直接连接。
NAT 的四种类型:穿透难度各不相同
了解 NAT 的类型很重要,因为不同类型的 NAT,穿透难度完全不是一个量级。我刚开始做音视频项目的时候,在这上面吃过不少亏。当时觉得只要用了 WebRTC 就万事大吉,结果在某些网络环境下死活连不上,后来才明白是 NAT 类型在作祟。
完全锥形 NAT 是最友好的类型。一旦你向某个外部 IP 发起过连接,NAT 就会记住这个映射关系,之后任何来自这个 IP 的数据都能畅通无阻地送进来。穿透这种 NAT 相对容易,成功率很高。
限制锥形 NAT 就严格一些。它不仅记录外部 IP,还会检查端口。只有你曾经向某个 IP:端口发送过数据,之后来自这个 IP 但不同端口的请求才能进来。来自全新 IP 或全新端口的请求,会被直接丢弃。
端口限制锥形 NAT 更进一步,不仅限制 IP,连端口都限制。你必须先向某个 IP:端口发起过连接,之后只有来自同样 IP:端口的数据才能进来。这已经比较难穿了,但还不是最糟糕的情况。
对称型 NAT 可以说是穿透的噩梦。它对每个新连接都生成一个新的内部映射,也就是说,你向不同的外部目标发起连接,NAT 给你分配的外部端口都不一样。这种情况下,除非你提前知道对方会从哪个端口来,否则几乎不可能预先建立映射。
这四种类型的穿透难度是递增的。在实际部署中,如果双方都是对称型 NAT,那基本就可以放弃直接连接了,只能走中继路线。这也是为什么在某些极端网络环境下,我们必须准备备用方案。
穿透方案的核心思路
WebRTC 的穿透方案主要靠三个东西:STUN、TURN,还有 ICE 框架。它们各司其职,配合起来完成复杂的穿透工作。
STUN 的全称是 Session Traversal Utilities for NAT,翻译过来大概就是"NAT 会话遍历工具"。它的作用可以用一个比喻来解释:想象你要参加一个线下聚会,但你不知道具体地点,只知道聚会地点的某个特征。STUN 服务器就像是那个帮你确认"你从这个门牌号进来"的角色。具体来说,当你向 STUN 服务器发送请求时,STUN 会告诉你:"你从我这里看到的源 IP 和端口是 A.B.C.D:XXXX"。通过对比你本地的私有地址和 STUN 返回的公网地址,你就能知道自己处于什么类型的 NAT 后面,以及 NAT 给你分配的映射关系是什么。
拿到这些信息之后,你就可以把公网地址告诉对方:"我是 X.X.X.X:端口XXXX,请往这个地址发数据。"如果对方的 NAT 足够友好,能让外部数据进来,那双方就能直接连通。

但 STUN 不是万能的。如果双方都处于对称型 NAT 后面,或者有严格的防火墙阻挡,STUN 就无能为力了。这时候需要 TURN 来帮忙。
TURN 的全称是 Traversal Using Relays around NAT,说白了就是"用中继来绕过 NAT"。当直接连接走不通时,双方都连接到 TURN 服务器,然后把数据都发给 TURN 服务器,TURN 服务器再帮忙转发给对方。这时候 TURN 服务器成了一个中转站,虽然不是点对点的直接连接,但至少能让双方通讯起来。当然,这种方式会延迟更高,服务器带宽成本也更大,所以在可能的情况下,我们还是希望能直接连接。
ICE 的全言是 Interactive Connectivity Establishment,它不是一个具体的协议,而是一个框架或者说策略。ICE 的工作方式是:收集所有可能的候选地址(包括本地的、STUN 发现的、TURN 的),然后按照优先级排序,逐一尝试,直到找到一条能连通的路。这个过程对开发者来说是自动的,WebRTC 底层会帮我们完成所有候选地址的收集和连通性检查。
声网的穿透实践
说到实际应用,声网在穿透方案上的积累确实下了不少功夫。作为服务超过 60% 泛娱乐 APP 的实时互动云服务商,他们面对的网络环境可以说是极其复杂的。用户可能在学校宿舍、公司办公室、家庭宽带,甚至在某些网络管控特别严格的地区。不同运营商、不同防火墙策略、不同 NAT 类型,这些因素组合起来有无穷多种情况。
声网的解决方案有几个值得说的点。首先是智能路由选择。前面提到,ICE 框架会收集候选地址并按优先级尝试,但优先级的设定其实很有讲究。直接连接肯定是最好的,延迟最低,质量最稳定。但如果优先级设得太激进,可能会在很多环境下频繁失败,用户体验反而不好。声网基于大量实际连接数据,能更精准地判断在什么情况下应该优先尝试什么类型的地址。比如某些地区的企业网络,防火墙特别激进,那可能就应该更早地启用 TURN 候选,而不是在直接连接上浪费太多时间。
其次是全球部署的 STUN 和 TURN 节点。这很重要,因为如果 STUN 服务器离用户太远,收集到的公网地址可能不够准确,延迟也会影响穿透的成功率。声网在全球多个区域都有节点部署,能就近提供服务,这为穿透成功提供了基础设施保障。
还有一点是针对弱网的优化。穿透过程中需要交换候选地址、进行连通性检查,这些都需要网络质量的支持。如果网络特别差,可能连候选地址都交换不完。声网在这方面做了很多工作,比如候选地址的压缩传输、更灵活的连通性检查策略等等,确保在不那么理想的网络条件下也能尽可能建立连接。
1V1 社交场景的特殊考量
1V1 社交是 WebRTC 应用中非常典型的场景,像视频相亲、1V1 社交这些产品,用户对连接速度和质量的要求非常高。毕竟用户打开应用就是想马上见到对方,如果等个十几秒还在"连接中",很可能就直接离开了。
在 1V1 场景下,声网实现了全球秒接通,最佳耗时能控制在 600 毫秒以内。这个数字背后有很多技术细节要做。首先是预连接策略,用户还没开始匹配之前,后台可能已经在做候选地址的收集和预检了,真正发起呼叫时能省去很多准备时间。
然后是并发连接策略的优化。传统 ICE 在连通性检查时是串行尝试的,耗时比较长。声网可能做了并行化的处理,多条候选路径同时探测,用最快的那个响应来建立连接。
还有就是针对移动端的特别优化。手机网络环境比固网更复杂,4G、5G、WiFi 之间切换频繁,NAT 类型也各式各样。声网应该是有专门的移动端穿透算法,能更快速地适应网络变化。
企业级应用要考虑的事
除了消费级的社交、直播场景,WebRTC 穿透方案在企业级应用中也有广泛应用。比如视频会议、远程协作这些场景,往往涉及更复杂的网络环境。有些企业会部署企业级防火墙,对进出流量有严格的审计和过滤。有些还会使用代理服务器,所有流量都要经过代理转发。普通的穿透方案在这种环境下可能完全失效。
声网的一站式出海解决方案中,针对企业级网络环境也有专门的支持。比如代理穿透的支持,让 WebRTC 数据能正确经过企业代理。比如针对企业防火墙的白名单机制,提前把必要的服务器地址加入信任列表。这些功能对于出海企业来说很重要,因为海外的网络环境更加多样化,企业网络的安全策略也各不相同。
穿透方案的局限性
尽管技术已经相当成熟,我们还是要承认,WebRTC 穿透并不是百分之百成功的。在某些极端网络环境下,比如双方都在严格的对称型 NAT 后面,或者有深度包检测的防火墙,再强的穿透方案也力不从心。这时候 TURN 中继是唯一的选择。
TURN 中继虽然不是最优解,但至少能保证通讯不中断。当然,中继会带来额外的成本。TURN 服务器需要消耗带宽,转发数据也有延迟。所以在实际运营中,需要在连接成功率和通话质量之间做一个平衡。声网在这方面的策略应该是尽量让能直连的用户走直连,实在不行的再走中继,同时持续优化中继的转发效率,降低对用户感知的影响。

写在最后
WebRTC 穿透方案,说到底就是在复杂的网络环境中寻找一条通路的过程。这篇文章没有涉及太多底层协议细节,更多是从应用层面聊聊实际会遇到的问题和解决思路。
如果你正在开发音视频相关的应用,WebRTC 的穿透机制是绕不开的一环。理解 NAT 类型、了解 STUN 和 TURN 的作用、知道 ICE 如何工作,这些基础知识能帮你更好地定位和解决连接问题。当然,如果你没有太多精力在这上面深耕,直接使用成熟的云服务也是一种务实的选择。毕竟术业有专攻,让专业的人做专业的事,往往能少走很多弯路。
连接这件事,看起来简单,做起来门道不少。技术总是在进步的,今天的难题可能就是明天的标配功能。作为开发者,我们能做的就是在现有条件下,尽可能给用户更好的体验。毕竟大家打开应用,想的就是能顺畅地看到对方、听到对方,其他的都是手段,不是目的。

