文章目录

  • 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方式穿越NATTURN应用模型通过分配TURNServer的地址和端口作为客户端对外的接受地址和端口,即私网用户发出的报文都要经过TURNServer进行Relay转发,这种方式应用模型除了具有STUN方式的优点外,还解决了STUN应用无法穿透对称NAT(SymmetricNAT)以及类似的Firewall设备的缺陷,即无论企业网/驻地网出口为哪种类型的NAT/FW,都可以实现NAT的穿透,同时TURN支持基于TCP的应用,如H323协议。此外TURNServer控制分配地址和端口,能分配RTP/RTCP地址对(RTCP端口号为RTP端口号加1)作为本端客户的接受地址,避免了STUN应用模型下出口NATRTP/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命令创建或管理ALLOCATIONallocation是服务器上的一个数据结构,包含了中继地址的信息。
服务器随后会给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)到服务器,然后服务器返回分配成功响应,并包含了分配的地址.客户端可以在属性字段描述其想要的分配类型(比如生命周期).由于中继数据实现了安全传输,服务器会要求对客户端进行验证,主要使用STUNlong-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 消息发送机制

ClientPeer之间有两种方法通过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提供了第二种方法来让clientpeer交互数据.该方法使用另一种数据包格式,即ChannelData message,信道数据报文.

ChannelData message不使用STUN头部,而使用一个4字节的头部,包含了一个称之为信道号的值(channel number).每一个使用中的信道号都与一个特定的peer绑定,即作为对等端地址的一个记号.

要将一个信道与对等端绑定,客户端首先发送一个信道绑定请求(ChannelBind Request)到服务器,并且指定一个未绑定的信道号以及对等端的地址信息.

绑定后clientserver都能通过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 编译安装

  1. 首先编译安装OpenSSL ,对应mac用户 macos10.12之前的系统都是系统自带的,macos10.12之后需要自己安装,openssl包含了很多加密,解密的处理算法。

打开终端,直接命令:

linux下:

sudo apt-get install libssl-dev

Mac下可以用brew install 安装:

brew install openssl

推荐你自己下载源码编译安装。

  1. 编译安装 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
  1. 安装 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 命令解压;
    依次使用 ./configuremakemake 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 目录下生成六个可执行文件:

  1. turnserver - STUN/TURN 服务器
  2. turnadmin - 用于配置、管理账户
  3. turnutils_stunclient - 用于测试 STUN 服务
  4. turnutils_uclient 用于测试 TURN 服务,模拟多个UDP、TCP、TLS 或 DTLS 类型的客户端
  5. turnutils_peer
  6. turnutils_rfc5769check

3.2 配置使用

coturn 支持三种配置:命令行、conf文件和数据库, 数据库支持sqlite,mysql,postgresql,MongoDB,redis。安装后的SQLite 数据库文件可能在 /usr/local/var/db/var/db/turndb 路径下,名称为 turndb 。

STUN 定义了两种验证方式:Long-Term CredentialShort-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协议相关推荐

  1. WebRTC源码研究(4)web服务器工作原理和常用协议基础

    文章目录 WebRTC源码研究(4)web服务器工作原理和常用协议基础 前言 做WebRTC 开发为啥要懂服务器开发知识 1. Web 服务器简介 2. Web 服务器的类型 3. Web 服务器的工 ...

  2. WebRTC源码研究(4)web服务器工作原理和常用协议基础(转载)

    前言 前面3篇博客分别对WebRTC框架的介绍,WebRTC源码目录,WebRTC的运行机制进行了介绍,接下来讲解一点关于服务器原理的知识.后面博客会写关于WebRTC服务器相关的开发,目前git上面 ...

  3. WebRTC源码研究(1)WebRTC架构

    文章目录 WebRTC源码研究(1)WebRTC架构 1. WebRTC简介 2. WebRTC的能力 2.1 抓住属于WebRTC的5G时代风口 2.1.1 浏览器的支持情况 2.1.2 大厂的加入 ...

  4. WebRTC源码研究(7)创建简单的HTTPS服务

    文章目录 WebRTC源码研究(7)创建简单的HTTPS服务 1. HTTPS简介 2. HTTPS 协议 3. HTTPS 证书 4. 创建简单的HTTPS服务 4.1 生成HTTPS证书 4.2 ...

  5. WebRTC源码研究(47)WebRCT传输非音视频数据

    文章目录 WebRTC源码研究(47)WebRCT传输非音视频数据 WebRTC源码研究(47)WebRCT传输非音视频数据

  6. 最新 WebRTC 源码目录结构分析

    前言 最近一直在研究 WebRTC源码,发现目前网上分析WebRTC源码的资料非常少.随着Google不断推进WebRTC标准,WebRTC 代码的变化非常大,很多以前的分析文章目前都与最新的代码无法 ...

  7. 关于谷歌webrtc源码国内镜像的使用问题,以及Kurento媒体服务器

     关于谷歌webrtc源码国内镜像的使用问题,以及Kurento媒体服务器 我周末搞了两天没搞出来码在国内有个镜像:https://source.codeaurora.org/quic/lc 但是 ...

  8. webrtc源码学习 - 点对点(P2P)链接过程(peer connection)

    创建PC pc 是 peer connection 的简写,以下文章中pc 都特指 peer connection PeerConnection 是webrtc 中链接过程非常重要的接口,提供了包括, ...

  9. Apache Camel源码研究之Rest

    本文以Camel2.24.3 + SpringBoot2.x 为基础简单解读Camel中的Rest组件的源码级实现逻辑. 0. 目录 1. 前言 2. 源码解读 2.1 启动时 2.1.1 `Rest ...

  10. 二、Neo4j源码研究系列 - 单步调试

    二.Neo4j源码研究系列 - 单步调试 一.背景介绍 上一篇我们已经把了neo4j的源码准备以及打包流程完成了,本篇将讲解如何对neo4j进行单步调试.对于不了解如何编译打包neo4j的读者,请阅读 ...

最新文章

  1. ASP.NET AJAX示例程序:实现IDragSource和IDropTarget接口将商品拖放至购物车中
  2. ZJOI2019游记
  3. ICCV 2019 | COCO-GAN:通过条件坐标的部分图像生成
  4. django+mysql+插入数据库网页展示内容
  5. 【转】SQLServer 游标简介与使用说明
  6. Android 学习资源收集
  7. angular4.0 父子组建之间的相互通信
  8. 聊聊 Tomcat 的单机多实例
  9. 让注册体验来得更简单点吧
  10. 将图片背景处理为透明的方法步骤
  11. 提高计算机性能的主流方法,提高cpu性能的方法有哪些?怎么把电脑cpu性能调到最大?...
  12. 模电笔记3 三极管 光电三极管
  13. 小卡,功能强大– M.2格式的工业通讯
  14. 杰奇小说站PC端跳转WAP端实现方式
  15. #clickid#CID#全新小程序链路CID/clickid解决方案,合规、完美防阿里封禁
  16. 快手与欧足联达成版权合作,获本赛季欧冠直播和短视频二创授权
  17. NAACL最佳方法论文:课本上的A*搜索算法可以提升文本生成效果!
  18. 示波器的各种文件存储方式与分析
  19. 优质的ppt图标素材推荐,不容错过
  20. 关于我国电子商务立法的思考

热门文章

  1. Android studio 下载SDK
  2. MySQL日期时间转换函数
  3. Python炸弹人小游戏源代码
  4. pyqt5设置dialog的标题_PyQt5教程——对话框(6)
  5. python可视化(十种常用图)
  6. 夜曲编程Python入门课程Pro
  7. 超详细的Java入门到精通完整学习教程,学Java一定得收藏。
  8. IDM下载器插件 让浏览器不在限速
  9. 【转载】世界上最牛的编辑器: Vim 3 (原创动图演示所有例子!)
  10. JDK API 1.6.0中文版直接下载