WebRTC源码研究(27)TURN协议
文章目录
- WebRTC源码研究(27)TURN协议
- 1. TURN协议简介
- 2. TURN 客户端,服务器处理流程
- 3. TURN 消息处理机制
- 3.1 TURN 消息发送机制
- 3.2 TURN 信道机制
- 3. TURN服务器搭建
- 3.1 编译安装
- 3.2 配置使用
- 3.2.1 配置 Long-Term 用户
- 3.2.2 启动服务器
- 3.2.3 测试 STUN
- 3.2.4 测试 TURN
- 3.2.5 开机启动服务
- 3.2.6 负载均衡
WebRTC源码研究(27)TURN协议
前面的章节中有讲到STUN
协议,P2P打洞原理,其实在P2P打洞这个章节中有讲解到TURN
协议,就是我们在NAT类型的四种类型中,对称性NAT我们是无法穿透的,在我们P2P 用常规的方式无法穿透时,我们才借助于STUN 转发,这样的代价是很大的。
由于STUN/RFC5389协议里能处理的也只有市面上大多数的Cone NAT(关于NAT类型可以参照P2P通信原理与实现),
对于对称性 NAT,传统的P2P打洞方法是不适用的。因此为了保证通信能够建立,我们可以在没办法的情况下用保证成功的中继方法(Relaying),虽然使用中继会对服务器负担加重,而且也算不上P2P,但是至少保证了最坏情况下信道的通畅,从而不至于受NAT类型的限制。TURN/RFC5766就是为此目的而进行的拓展。
本篇主要详细讲解TURN
协议,具体更多细节可以参考官方文档:TURN/RFC5766 下载相关pdf细细品阅。
关于TURN Server有很多现成的开源代码,你可以从这里下载一个研究研究:TURN Server
- coturn/rfc5766-turn-server
- coturn
1. TURN协议简介
TURN
协议允许NAT
或者防火墙后面的对象可以通过TCP
或者UDP
接收到数据。这在使用了对称式的NAT(或者防火墙)
的网络中尤其具有实用价值 。
TURN
方式解决NAT
问题的思路与STUN
相似,是基于私网接入用户通过某种机制预先得到其私有地址对应在公网的地址(STUN方式得到的地址为出口NAT上的地址,TURN方式得到地址为TURNServer上的地址
),然后在报文负载中所描述的地址信息直接填写该公网地址的方式,实际应用原理也是一样的。
TURN
的全称为Traversal Using Relay NAT
,即通过Relay方式穿越NAT,TURN
应用模型通过分配TURNServer
的地址和端口作为客户端对外的接受地址和端口,即私网用户发出的报文都要经过TURNServer
进行Relay转发,这种方式应用模型除了具有STUN
方式的优点外,还解决了STUN
应用无法穿透对称NAT(SymmetricNAT)以及类似的Firewall设备的缺陷,即无论企业网/驻地网出口为哪种类型的NAT/FW,都可以实现NAT的穿透,同时TURN
支持基于TCP
的应用,如H323
协议。此外TURNServer
控制分配地址和端口,能分配RTP/RTCP
地址对(RTCP
端口号为RTP
端口号加1)作为本端客户的接受地址,避免了STUN
应用模型下出口NAT
对RTP/RTCP
地址端口号的任意分配,使得客户端无法收到对端发过来的RTCP
报文(对端发RTCP
报文时,目的端口号缺省按RTP
端口号加1发送)
TURN
的局限性在于所有报文都必须经过TURNServer
转发,增大了包的延迟和丢包的可能性。
2. TURN 客户端,服务器处理流程
我在前面的博客“[WebRTC源码研究(25)NAT打洞原理]” 中有讲解到TURN 相关的流程,这里再详细讲解一下,更多细节可以参考官方文档:TURN/RFC5766
在典型的情况下,TURN
客户端连接到内网中,并且通过一个或者多个NAT
到达公网,TURN服务器
架设在公网中,不同的客户端以TURN服务器
为中继和其他peer进行通信,如下图所示:
Peer AServer-Reflexive +---------+Transport Address | |192.0.2.150:32102 | || /| |TURN | / ^| Peer A |Client’s Server | / || |Host Transport Transport | // || |Address Address | // |+---------+10.1.1.2:49721 192.0.2.15:3478 |+-+ // Peer A| | ||N| / Host Transport| +-+ | ||A|/ Address| | | | v|T| 192.168.100.2:49582| | | | /+-++---------+| | | |+---------+ / +---------+| || |N| || | // | || TURN |v | | v| TURN |/ | || Client |----|A|----------| Server |------------------| Peer B || | | |^ | |^ ^| || | |T|| | || || |+---------+ | || +---------+| |+---------+| || | || || | |+-+| | || | || | |Client’s | Peer BServer-Reflexive Relayed TransportTransport Address Transport Address Address192.0.2.1:7000 192.0.2.15:50000 192.0.2.210:49191
在上图中,左边的TURN Client
是位于NAT
后面的一个客户端(内网地址是10.1.1.2:49721),连接公网的TURN服务器
(默认端口3478)后,
服务器会得到一个Client
的反射地址(Reflexive Transport Address
, 即NAT分配的公网IP和端口)192.0.2.1:7000,此时Client
会通过TURN
命令创建或管理ALLOCATION
,allocation
是服务器上的一个数据结构,包含了中继地址的信息。
服务器随后会给Client
分配一个中继地址,即图中的192.0.2.15:50000,另外两个对等端若要通过TURN
协议和Client
进行通信,可以直接往中继地址收发数据即可,TURN服务器
会把发往指定中继地址的数据转发到对应的Client
,这里是其反射地址。
Server
上的每一个allocation
都唯一对应一个client
,并且只有一个中继地址,因此当数据包到达某个中继地址时,服务器总是知道应该将其转发到什么地方。
但值得一提的是,一个Client
可能在同一时间在一个Server
上会有多个allocation
,这和上述规则是并不矛盾的。
传输
在协议中,TURN
服务器与peer
之间的连接都是基于UDP
的,但是服务器和客户端之间可以通过其他各种连接来传输STUN报文,比如TCP/UDP/TLS-over-TCP.
客户端之间通过中继传输数据时候,如果用了TCP
,也会在服务端转换为UDP
,因此建议客户端使用UDP
来进行传输. 至于为什么要支持TCP
,那是因为一部分防火墙会完全阻挡UDP
数据,而对于三次握手的TCP
数据则不做隔离.分配(Allocations)
要在服务器端获得一个中继分配,客户端须使用分配事务. 客户端发送分配请求(Allocate request
)到服务器,然后服务器返回分配成功响应,并包含了分配的地址.客户端可以在属性字段描述其想要的分配类型(比如生命周期).由于中继数据实现了安全传输,服务器会要求对客户端进行验证,主要使用STUN
的long-term credential mechanism
.
一旦中继传输地址分配好,客户端必须要将其保活.通常的方法是发送刷新请求(Refresh request
)到服务端.这在TURN
中是一个标准的方法.刷新频率取决于分配的生命期,默认为10分钟
.客户端也可以在刷新请求里指定一个更长的生命期,而服务器会返回一个实际上分配的时间. 当客户端想中指通信时,可以发送一个生命期为0的刷新请求.服务器和客户端都保存有一个成为五元组(5-TUPLE
)的信息,比如对于客户端来说,五元组包括客户端本地地址/端口,服务器地址/端口,和传输协议;服务器也是类似,只不过将客户端的地址变为其反射地址,因为那才是服务器所见到的. 服务器和客户端在分配请求中都带有5-TUPLE
信息,并且也在接下来的信息传输中使用,因此彼此都知道哪一次分配对应哪一次传输.
如下图所示,客户端首先发送Allocate
请求,但是没带验证信息,因此STUN
服务器会返回error response
,客户端收到错误后加上所需的验证信息再次请求,才能进行成功的分配.
TURN TURN Peer Peer
client server A B|-- Allocate request --------------->| | || | | ||<--------------- Allocate failure --| | || (401 Unauthorized) | | || | | ||-- Allocate request --------------->| | || | | ||<---------- Allocate success resp --| | || (192.0.2.15:50000) | | |// // // //| | | ||-- Refresh request ---------------->| | || | | ||<----------- Refresh success resp --| | || | | |
3. TURN 消息处理机制
3.1 TURN 消息发送机制
Client
和Peer
之间有两种方法通过TURN server
交换应用信息:
- 第一种: 是使用Send和Data方法(method)
- 第二种: 是使用通道(channels)
两种方法都通过某种方式告知服务器哪个peer应该接收数据,以及服务器告知client数据来自哪个peer.
Send Mechanism
使用了Send和Data指令(Indication
).其中Send指令用来把数据从client
发送到server
,而Data指令用来把数据从
server
发送到client
.当使用Send指令时,客户端发送一个Send Indication
到服务端,其中包含:
XOR-PEER-ADDRESS
属性,指定对等端的(服务器反射)地址.- DATA属性,包含要传给对等端的信息.
当服务器收到Send Indication
之后,会将DATA
部分的数据解析出来,并将其以UDP
的格式转发到对应的端点去,并且在封装数据包的时候把client
的中继地址作为源地址.从而从对等端发送到中继地址的数据也会被服务器转发到client
上.
值得一提的是,Send/Data Indication
是不支持验证的,因为长效验证机制不支持对indication
的验证,因此为了防止攻击,TURN
要求client
在给对等端发送indication
之前先安装一个到对等端的许可(permission
),
如下图所示,client到Peer B
没有安装许可,导致其indication
数据包将被服务器丢弃,对于peer B
也是同样:
TURN TURN Peer Peer
client server A B| | | ||-- CreatePermission req (Peer A) -->| | ||<-- CreatePermission success resp --| | || | | ||--- Send ind (Peer A)-------------->| | || |=== data ===>| || | | || |<== data ====| ||<-------------- Data ind (Peer A) --| | || | | || | | ||--- Send ind (Peer B)-------------->| | || | dropped | || | | || |<== data ==================|| dropped | | || | | |
3.2 TURN 信道机制
对于一些应用程序,比如VOIP(Voice over IP),
在Send/Data Indication
中多加的36字节格式信息会加重客户端和服务端之间的带宽压力.
为改善这种情况,TURN
提供了第二种方法来让client
和peer
交互数据.该方法使用另一种数据包格式,即ChannelData message,信道数据报文.
ChannelData message
不使用STUN
头部,而使用一个4字节的头部,包含了一个称之为信道号的值(channel number
).每一个使用中的信道号都与一个特定的peer
绑定,即作为对等端地址的一个记号.
要将一个信道与对等端绑定,客户端首先发送一个信道绑定请求(ChannelBind Request
)到服务器,并且指定一个未绑定的信道号以及对等端的地址信息.
绑定后client
和server
都能通过ChannelData message
来发送和转发数据.信道绑定默认持续10分钟,并且可以通过重新发送ChannelBind Request
来刷新持续时间.和Allocation
不同的是,并没有直接删除绑定的方法,只能等待其超时自动失效.
TURN TURN Peer Peer
client server A B| | | ||-- ChannelBind req ---------------->| | || (Peer A to 0x4001) | | || | | ||<---------- ChannelBind succ resp --| | || | | ||-- [0x4001] data ------------------>| | || |=== data ===>| || | | || |<== data ====| ||<------------------ [0x4001] data --| | || | | ||--- Send ind (Peer A)-------------->| | || |=== data ===>| || | | || |<== data ====| ||<------------------ [0x4001] data --| | || | | |
上图中0x4001
为信道号,即ChannelData message
的头部中头2字节,值得一提的是信道号的选取有如下要求:
0x0000-0x3FFF
: 这一段的值不能用来作为信道号0x4000-0x7FFF
: 这一段是可以作为信道号的值,一共有16383种不同值在目前来看是足够用的0x8000-0xFFFF
: 这一段是保留值,留给以后使用
3. TURN服务器搭建
3.1 编译安装
- 首先编译安装OpenSSL ,对应mac用户 macos10.12之前的系统都是系统自带的,macos10.12之后需要自己安装,openssl包含了很多加密,解密的处理算法。
打开终端,直接命令:
linux下:
sudo apt-get install libssl-dev
Mac下可以用brew install 安装:
brew install openssl
推荐你自己下载源码编译安装。
- 编译安装 libevent 最新版;
wget https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
tar xvfz libevent-2.0.21-stable.tar.gz
cd libevent-2.0.21-stable
./configure
make
sudo make install
- 安装 coturn :
coturn
可以选择使用多种数据库,这里使用的是SQLite
,使用命令sudo apt-get install sqlite (or sqlite3)
和sudo apt-get install libsqlite3-dev (or sqlite3-dev)
安装;
编译coturn
: 在 coturn 下载页 下载最新正式版本的 cotrun 源码,下载完成后使用tar xvfz turnserver-<...>.tar.gz
命令解压;
依次使用./configure
、make
和make install
编译安装 coturn 。
tar xvfz turnserver-<...>.tar.gz
./configure
make
sudo make install
你也可以直接命令下载编译coturn:
git clone https://github.com/coturn/coturn
cd coturn
./configure
make
make install
输入which turnserver,如果打印出路径,说明安装成功
安装完成后在 bin 目录下生成六个可执行文件:
- turnserver - STUN/TURN 服务器
- turnadmin - 用于配置、管理账户
- turnutils_stunclient - 用于测试 STUN 服务
- turnutils_uclient 用于测试 TURN 服务,模拟多个UDP、TCP、TLS 或 DTLS 类型的客户端
- turnutils_peer
- turnutils_rfc5769check
3.2 配置使用
coturn 支持三种配置:命令行、conf文件和数据库, 数据库支持sqlite,mysql,postgresql,MongoDB,redis
。安装后的SQLite 数据库文件可能在 /usr/local/var/db
或 /var/db/turndb
路径下,名称为 turndb 。
STUN 定义了两种验证方式:Long-Term Credential
和 Short-Term Credential
。
具体可以参考 STUN 标准 http://tools.ietf.org/html/rfc5389#section-15.4 。但是对于 WebRTC 而言,仅支持 Long-Term Credential 。
- 配置coturn
使用turnadmin生成安全访问密码
#使用turnadmin生成安全访问密码
turnadmin -k -u username -r north.gov -p password
/usr/local/etc/turnserver.conf配置
#listening-ip与relay-ip采用内网ip,external-ip是外网的iplistening-port=444 #监听端口
external-ip=210.21.53.158 #外网IP
verbose
fingerprint
lt-cred-mech
realm=test
user=username:生成的加密密码 #修改成自己的
user=username:password #修改成自己的
stale-nonce
no-loopback-peers
no-multicast-peers
mobility
no-cli
- 启动coturn
turnserver -o -a
3.2.1 配置 Long-Term 用户
首先使用下列命令添加一个 Long-Term 用户:
sudo turnadmin -a -u you_name -p you_password -r you_realm
这里默认使用了 SQLite 数据库,其中 -a 表示添加一个 long-term 用户, -u 为用户名,-p 为密码,-r 为该用户所属的 Realm。在启动 turnserver 时需要指定 Realm ,只有该 Realm 下的用户才能登录。
注意一定要使用 root 权限配置,否则会配置失败,但是还没有错误提示。
3.2.2 启动服务器
配置完用户后就可以启动 turnserver 了,第一次启动前需要一个配置文件,这是使用模板生成,然后就可以启动 turnserver 了。
sudo cp /usr/local/etc/turnserver.conf.default /usr/local/etc/turnserver.conf
sudo turnserver -a -f -v -r you_realm
其中 -a 表示使用 long-term 机制, -r 为指定的 Realm ,只有该 Realm 下的用户可以使用服务器。
3.2.3 测试 STUN
使用下面的命令即可测试 STUN 服务使用可用,唯一此参数是 STUN 服务器的 IP地址或域名。
# 测试 STUN
turnutils_stunclient 123.166.110.69
3.2.4 测试 TURN
使用下面的命令即可测试 TURN 服务使用可用,值得注意的是必须使用 turnserver 启动时指定 Realm 下的用户。
# 测试 TURN
turnutils_uclient -u cjx -w 123456 123.166.110.69
也可以使用 Google 提供的 WebRTC STUN/TURN 测试页面进行测试:https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ 。
3.2.5 开机启动服务
如果想要开机启动 turnserver,首先需要修改配置文件 turnserver.config,一般情况需要修改以下的几个参数:
listening-ip=127.0.0.1
listening-ip=172.16.0.99 # 内网ip
external-ip=221.208.117.45 # 公网ip,如果服务器在NAT后需要指定该参数
fingerprint
lt-cred-mech
realm=<you_realm_name>
在手动修改好配置文件 turnserver.config 后,Ubuntu 14.04 系统下可以使用下列命令添加开机启动项:
sudo update-rc.d turnserver defaults
如果发生 update-rc.d: /etc/init.d/turnserver : file does not exist 错误,执行下列命令创建一个软链接即可:
sudo ln -sf /usr/local/bin/turnsever /etc/init.d/turnserver
添加/etc/systemd/system/turnserver.service
[Unit]
Description=coturn
Documentation=man:coturn(1) man:turnadmin(1) man:turnserver(1)
After=syslog.target network.target[Service]
Type=forking
PIDFile=/var/run/turnserver.pid
ExecStart=/usr/local/bin/turnserver --daemon --pidfile /var/run/turnserver.pid -c /etc/turnserver.conf
ExecStopPost=/usr/bin/rm -f /var/run/turnserver.pid
Restart=on-abortLimitCORE=infinity
LimitNOFILE=999999
LimitNPROC=60000
LimitRTPRIO=infinity
LimitRTTIME=7000000
CPUSchedulingPolicy=other
然后执行以下命令:
# 使服务自动启动
sudo systemctl enable turnserver.service
# 启动服务
sudo systemctl start turnserver
# 停止服务
sudo systemctl stop turnserver
3.2.6 负载均衡
coturn 可以通过设置一个 master turn server ,配置若干个 slave turn server 的方式实现负载均衡。
master 服务器只需在启动时指定 --alternate-server 和 --tls-alternate-server 参数即可,具体使用方法可以查看 source/examples/scripts/loadbalance
目录下的几个文件。
参考文章:https://blog.csdn.net/kenn1117/article/details/72822803
https://github.com/rainzhaojy/blogs/issues/4
https://github.com/coturn/coturn/wiki/CoturnConfig
搭建WebRtc服务器
WebRTC源码研究(27)TURN协议相关推荐
- WebRTC源码研究(4)web服务器工作原理和常用协议基础
文章目录 WebRTC源码研究(4)web服务器工作原理和常用协议基础 前言 做WebRTC 开发为啥要懂服务器开发知识 1. Web 服务器简介 2. Web 服务器的类型 3. Web 服务器的工 ...
- WebRTC源码研究(4)web服务器工作原理和常用协议基础(转载)
前言 前面3篇博客分别对WebRTC框架的介绍,WebRTC源码目录,WebRTC的运行机制进行了介绍,接下来讲解一点关于服务器原理的知识.后面博客会写关于WebRTC服务器相关的开发,目前git上面 ...
- WebRTC源码研究(1)WebRTC架构
文章目录 WebRTC源码研究(1)WebRTC架构 1. WebRTC简介 2. WebRTC的能力 2.1 抓住属于WebRTC的5G时代风口 2.1.1 浏览器的支持情况 2.1.2 大厂的加入 ...
- WebRTC源码研究(7)创建简单的HTTPS服务
文章目录 WebRTC源码研究(7)创建简单的HTTPS服务 1. HTTPS简介 2. HTTPS 协议 3. HTTPS 证书 4. 创建简单的HTTPS服务 4.1 生成HTTPS证书 4.2 ...
- WebRTC源码研究(47)WebRCT传输非音视频数据
文章目录 WebRTC源码研究(47)WebRCT传输非音视频数据 WebRTC源码研究(47)WebRCT传输非音视频数据
- 最新 WebRTC 源码目录结构分析
前言 最近一直在研究 WebRTC源码,发现目前网上分析WebRTC源码的资料非常少.随着Google不断推进WebRTC标准,WebRTC 代码的变化非常大,很多以前的分析文章目前都与最新的代码无法 ...
- 关于谷歌webrtc源码国内镜像的使用问题,以及Kurento媒体服务器
关于谷歌webrtc源码国内镜像的使用问题,以及Kurento媒体服务器 我周末搞了两天没搞出来码在国内有个镜像:https://source.codeaurora.org/quic/lc 但是 ...
- webrtc源码学习 - 点对点(P2P)链接过程(peer connection)
创建PC pc 是 peer connection 的简写,以下文章中pc 都特指 peer connection PeerConnection 是webrtc 中链接过程非常重要的接口,提供了包括, ...
- Apache Camel源码研究之Rest
本文以Camel2.24.3 + SpringBoot2.x 为基础简单解读Camel中的Rest组件的源码级实现逻辑. 0. 目录 1. 前言 2. 源码解读 2.1 启动时 2.1.1 `Rest ...
- 二、Neo4j源码研究系列 - 单步调试
二.Neo4j源码研究系列 - 单步调试 一.背景介绍 上一篇我们已经把了neo4j的源码准备以及打包流程完成了,本篇将讲解如何对neo4j进行单步调试.对于不了解如何编译打包neo4j的读者,请阅读 ...
最新文章
- ASP.NET AJAX示例程序:实现IDragSource和IDropTarget接口将商品拖放至购物车中
- ZJOI2019游记
- ICCV 2019 | COCO-GAN:通过条件坐标的部分图像生成
- django+mysql+插入数据库网页展示内容
- 【转】SQLServer 游标简介与使用说明
- Android 学习资源收集
- angular4.0 父子组建之间的相互通信
- 聊聊 Tomcat 的单机多实例
- 让注册体验来得更简单点吧
- 将图片背景处理为透明的方法步骤
- 提高计算机性能的主流方法,提高cpu性能的方法有哪些?怎么把电脑cpu性能调到最大?...
- 模电笔记3 三极管 光电三极管
- 小卡,功能强大– M.2格式的工业通讯
- 杰奇小说站PC端跳转WAP端实现方式
- #clickid#CID#全新小程序链路CID/clickid解决方案,合规、完美防阿里封禁
- 快手与欧足联达成版权合作,获本赛季欧冠直播和短视频二创授权
- NAACL最佳方法论文:课本上的A*搜索算法可以提升文本生成效果!
- 示波器的各种文件存储方式与分析
- 优质的ppt图标素材推荐,不容错过
- 关于我国电子商务立法的思考