TURN协议详解:从原理到实践

大家好,我是你们的WebRTC讲师。今天我们来聊聊TURN协议——这个在WebRTC穿透技术里最"笨"但也最可靠的角色。

说到TURN,我印象特别深。几年前做一款跨国视频会议产品,STUN和ICE都搞定了,结果在某个中东客户的网络环境里就是连不上。折腾了两天,最后发现是他们的企业防火墙太严格,UDP全封了。没办法,只能上TURN。嗯,从那以后我就再也不敢小看这个"笨办法"了。

TURN协议概述

TURN,全称是Traversal Using Relays around NAT。说白了,就是当P2P走不通的时候,我们找个服务器当"中间人"。

你想想看,STUN能帮你拿到公网地址,ICE能帮你尝试各种路径。但有些网络环境实在太"变态"——对称NAT、防火墙封UDP、甚至封了所有非标准端口。这时候,TURN就是最后的救命稻草。

TURN的核心思想很简单:

  • 客户端和TURN服务器建立连接
  • 服务器分配一个中继地址
  • 所有数据都通过服务器转发

代价呢?带宽成本翻倍,延迟增加。但至少能通。

关键点:TURN不是用来替代STUN的,而是作为ICE流程中的最后候选。我建议你在实际项目中,优先尝试STUN,实在不行再fallback到TURN。

TURN消息结构

TURN协议基于STUN协议扩展而来。它的消息格式和STUN很像,但多了几个特有的属性。

先看基本结构:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         STUN 消息头 (20字节)                                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         属性 (可变长度)                                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

消息头里有个关键字段叫"Method",TURN定义了自己的方法:

方法名 方法值 作用
Allocate 0x003 请求分配中继地址
Refresh 0x004 刷新中继地址的租期
Send 0x006 通过中继发送数据
Data 0x007 从中继接收数据
CreatePermission 0x008 创建对端权限
ChannelBind 0x009 绑定通道号

我个人习惯把TURN的消息分为两类:控制消息和数据消息。控制消息负责建立和维护中继连接,数据消息负责实际传输。

小技巧:TURN的Allocate请求里有个LIFETIME属性,默认是10分钟。如果你在项目中遇到连接突然断开,先检查是不是租期到了没刷新。我曾经因为这个坑调试了一下午。

TURN中继原理

中继的原理其实不复杂。我画个图帮你理解:

TURN中继原理示意图 客户端A 192.168.1.10:5000 NAT A (对称型) 客户端B 10.0.0.5:8000 NAT B (对称型) TURN服务器 中继地址: 203.0.113.5:3478 数据流:A → TURN → B P2P直连失败,走中继转发 对称NAT之间无法直接穿透 所有媒体数据经过TURN服务器中转 带宽成本:发送方1份 + 接收方1份 = 2份流量

流程是这样的:

  1. 分配中继地址:客户端A发送Allocate请求给TURN服务器,服务器返回一个公网中继地址。
  2. 创建权限:A告诉服务器"我要和B通信",服务器创建对应的权限条目。
  3. 数据转发:A把数据发给TURN服务器,服务器再转发给B。反过来也一样。

这里有个细节要注意:TURN支持两种数据发送方式——Send/Data机制和Channel机制。Send/Data机制每次都要带完整的地址信息,而Channel机制可以预先绑定一个通道号,后续发送只需要带通道号就行,省带宽。

避坑指南:我曾经在一个项目中,客户端频繁发送小数据包,用的都是Send机制。结果每个包都带完整的地址信息,带宽浪费了30%以上。后来改成Channel机制,问题立刻解决。所以,如果你的应用有很多小数据包,一定要用Channel机制。

TURN的优缺点

任何技术都有两面性。TURN也不例外。

优点

  • 穿透率最高:几乎能穿透所有NAT和防火墙。我做过测试,在极端网络环境下,TURN的穿透率接近100%。
  • 实现简单:服务器只需要做转发,不需要维护复杂的NAT映射表。
  • 安全性好:所有流量都经过认证的服务器,可以做一些安全策略。
  • 支持TCP:当UDP被封锁时,TURN可以跑在TCP上,甚至TLS上。

缺点

  • 延迟高:数据多跳一次,延迟至少增加20-50ms。如果是跨国中继,可能到100ms以上。
  • 带宽成本高:服务器需要同时接收和发送,带宽消耗是P2P的两倍。假设你有1000个用户同时通话,每个用户1Mbps,那服务器带宽就要2Gbps。这成本...你懂的。
  • 单点故障:所有流量都经过TURN服务器,服务器挂了所有连接都断。所以生产环境一定要做集群和冗余。
  • 扩展性差:随着用户量增长,服务器压力线性增加。不像P2P,用户越多网络越强。

我的建议:在实际项目中,不要把TURN当作默认方案。ICE的优先级顺序应该是:

  1. host(本地地址)
  2. srflx(STUN反射地址)
  3. relay(TURN中继地址)

只有在前面两种都失败的情况下,才使用TURN。这样可以最大程度降低成本,同时保证连通性。

说到成本,我记得有个项目为了省钱,把TURN服务器部署在海外,结果国内用户延迟高得离谱。后来我们在国内也部署了TURN服务器,延迟从200ms降到了30ms。所以,TURN服务器的地理位置很重要,尽量靠近用户。

好了,TURN协议的核心内容就这些。总结一下:TURN是WebRTC穿透技术的最后一道防线,虽然成本高、延迟大,但胜在可靠。在实际项目中,合理配置ICE的优先级,让TURN只作为兜底方案,就能在成本和连通性之间找到平衡。

最后提醒:如果你自己搭建TURN服务器,推荐用coturn这个开源项目。我用了好几年,稳定性和性能都不错。配置的时候记得开启认证,不然你的服务器可能被当成免费代理用。

公众号:蓝海资料掘金营,微信deep3321