欢迎光临
我们一直在努力

TURN: 中继服务器详解

TURN: 中继服务器详解

本文是 WebRTC 系列专栏的第十篇,将深入剖析 TURN 协议的工作原理、数据中继流程以及如何使用 coturn 搭建生产级 TURN 服务器。


目录

  • TURN 概述
  • TURN 协议详解
  • TURN 数据中继流程
  • TURN 认证机制
  • coturn 安装与配置
  • 生产环境部署
  • 总结

  • 1. TURN 概述

    1.1 什么是 TURN

    TURN (Traversal Using Relays around NAT) 是 STUN 的扩展协议,定义在 RFC 5766 中。当 P2P 直连失败时,TURN 服务器作为中继,转发双方的媒体数据。

    1.2 为什么需要 TURN

    ┌─────────────────────────────────────────────────────────────────────────┐
    │ TURN 的必要性 │
    ├─────────────────────────────────────────────────────────────────────────┤
    │ │
    │ 场景: 两端都是 Symmetric NAT,无法直接穿透 │
    │ │
    │ 用户 A 用户 B │
    │ (Symmetric NAT) (Symmetric NAT) │
    │ │ │ │
    │ │ P2P 穿透失败 │ │
    │ │ ─────────────────── X ──────────────────────────│ │
    │ │ │ │
    │ │ │ │
    │ │ ┌─────────────────┐ │ │
    │ │ │ TURN 服务器 │ │ │
    │ │ │ (公网 IP) │ │ │
    │ │ └────────┬────────┘ │ │
    │ │ │ │ │
    │ │ 中继连接 │ 中继连接 │ │
    │ │ ─────────────────────>│<─────────────────────── │ │
    │ │ │ │ │
    │ │ 数据通过 TURN 中继 │ │ │
    │ │ <═══════════════════════════════════════════════>│ │
    │ │ │ │
    └─────────────────────────────────────────────────────────────────────────┘

    1.3 TURN vs STUN

    特性STUNTURN
    功能 发现公网地址 中继数据
    数据流 不经过服务器 经过服务器
    带宽消耗 极低 高 (所有数据)
    成本
    适用场景 NAT 可穿透 NAT 不可穿透
    延迟 较高

    1.4 TURN 在 ICE 中的角色

    ┌─────────────────────────────────────────────────────────────────────────┐
    │ ICE 候选优先级 │
    ├─────────────────────────────────────────────────────────────────────────┤
    │ │
    │ 优先级从高到低: │
    │ │
    │ 1. host (本地地址) ──> 最快,直接连接 │
    │ 2. srflx (STUN 反射地址) ──> P2P 穿透 │
    │ 3. prflx (对端反射地址) ──> 动态发现 │
    │ 4. relay (TURN 中继地址) ──> 保底方案,确保连通 │
    │ │
    │ TURN 作为最后的保障: │
    │ – 当所有 P2P 尝试失败时使用 │
    │ – 确保 100% 的连通性 │
    │ – 代价是更高的延迟和带宽成本 │
    │ │
    └─────────────────────────────────────────────────────────────────────────┘


    2. TURN 协议详解

    2.1 TURN 消息类型

    TURN 扩展了 STUN 的消息类型:

    方法值说明
    Allocate 0x003 请求分配中继地址
    Refresh 0x004 刷新分配
    Send 0x006 发送数据 (Indication)
    Data 0x007 接收数据 (Indication)
    CreatePermission 0x008 创建权限
    ChannelBind 0x009 绑定通道

    2.2 Allocate 请求

    客户端首先发送 Allocate 请求,获取中继地址。

    ┌─────────────────────────────────────────────────────────────────────────┐
    │ Allocate 请求流程 │
    ├─────────────────────────────────────────────────────────────────────────┤
    │ │
    │ 客户端 TURN 服务器 │
    │ │ │ │
    │ │ 1. Allocate Request │ │
    │ │ (无认证) │ │
    │ │ ──────────────────────────────────────────────────> │ │
    │ │ │ │
    │ │ 2. Allocate Error Response (401) │ │
    │ │ REALM, NONCE │ │
    │ │ <────────────────────────────────────────────────── │ │
    │ │ │ │
    │ │ 3. Allocate Request │ │
    │ │ USERNAME, REALM, NONCE, MESSAGE-INTEGRITY │ │
    │ │ ──────────────────────────────────────────────────> │ │
    │ │ │ │
    │ │ 4. Allocate Success Response │ │
    │ │ XOR-RELAYED-ADDRESS: 198.51.100.1:49152 │ │
    │ │ XOR-MAPPED-ADDRESS: 1.2.3.4:12345 │ │
    │ │ LIFETIME: 600 │ │
    │ │ <────────────────────────────────────────────────── │ │
    │ │ │ │
    └─────────────────────────────────────────────────────────────────────────┘

    2.3 TURN 特有属性

    属性类型值说明
    CHANNEL-NUMBER 0x000C 通道号
    LIFETIME 0x000D 分配生存时间
    XOR-PEER-ADDRESS 0x0012 对端地址
    DATA 0x0013 数据
    XOR-RELAYED-ADDRESS 0x0016 中继地址
    REQUESTED-TRANSPORT 0x0019 请求的传输协议
    DONT-FRAGMENT 0x001A 不分片
    RESERVATION-TOKEN 0x0022 预留令牌

    2.4 分配 (Allocation)

    分配是 TURN 的核心概念,表示服务器为客户端分配的中继资源。

    ┌─────────────────────────────────────────────────────────────────────────┐
    │ TURN 分配结构 │
    ├─────────────────────────────────────────────────────────────────────────┤
    │ │
    │ 客户端 TURN 服务器 │
    │ 1.2.3.4:12345 198.51.100.1 │
    │ │ │ │
    │ │ │ │
    │ │ 分配 (Allocation) │ │
    │ │ ┌─────────────────────────┴─────────────────────────┐ │
    │ │ │ │ │
    │ │ │ 中继地址: 198.51.100.1:49152 │ │
    │ │ │ 客户端地址: 1.2.3.4:12345 │ │
    │ │ │ 生存时间: 600 秒 │ │
    │ │ │ 权限列表: [] │ │
    │ │ │ 通道绑定: [] │ │
    │ │ │ │ │
    │ │ └───────────────────────────────────────────────────┘ │
    │ │ │ │
    │ │ │ │
    │ │ 对端可以向 198.51.100.1:49152 发送数据 │
    │ │ TURN 服务器会转发给客户端 │
    │ │ │ │
    └─────────────────────────────────────────────────────────────────────────┘

    2.5 权限 (Permission)

    客户端必须为每个对端创建权限,才能接收来自该对端的数据。

    ┌─────────────────────────────────────────────────────────────────────────┐
    │ CreatePermission 流程 │
    ├─────────────────────────────────────────────────────────────────────────┤
    │ │
    │ 客户端 TURN 服务器 │
    │ │ │ │
    │ │ 1. CreatePermission Request │ │
    │ │ XOR-PEER-ADDRESS: 5.6.7.8 (对端 IP) │ │
    │ │ ──────────────────────────────────────────────────> │ │
    │ │ │ │
    │ │ 2. CreatePermission Success Response │ │
    │ │ <────────────────────────────────────────────────── │ │
    │ │ │ │
    │ │ 权限已创建: │ │
    │ │ – 允许接收来自 5.6.7.8 的数据 │ │
    │ │ – 权限有效期: 300 秒 │ │
    │ │ – 需要定期刷新 │ │
    │ │ │ │
    └─────────────────────────────────────────────────────────────────────────┘

    2.6 通道绑定 (Channel Binding)

    通道绑定可以减少数据传输的开销。

    ┌─────────────────────────────────────────────────────────────────────────┐
    │ ChannelBind 流程 │
    ├─────────────────────────────────────────────────────────────────────────┤
    │ │
    │ 客户端 TURN 服务器 │
    │ │ │ │
    │ │ 1. ChannelBind Request │ │
    │ │ CHANNEL-NUMBER: 0x4001 │ │
    │ │ XOR-PEER-ADDRESS: 5.6.7.8:54321 │ │
    │ │ ──────────────────────────────────────────────────> │ │
    │ │ │ │
    │ │ 2. ChannelBind Success Response │ │
    │ │ <────────────────────────────────────────────────── │ │
    │ │ │ │
    │ │ 通道已绑定: │ │
    │ │ – 通道号 0x4001 绑定到 5.6.7.8:54321 │ │
    │ │ – 可以使用 ChannelData 消息发送数据 │ │
    │ │ – 开销从 36 字节降低到 4 字节 │ │
    │ │ │ │
    └─────────────────────────────────────────────────────────────────────────┘

    通道号范围: 0x4000 – 0x7FFF


    3. TURN 数据中继流程

    3.1 Send/Data Indication

    使用 Send Indication 发送数据,使用 Data Indication 接收数据。

    ┌─────────────────────────────────────────────────────────────────────────┐
    │ Send/Data Indication 流程 │
    ├─────────────────────────────────────────────────────────────────────────┤
    │ │
    │ 客户端 A TURN 服务器 客户端 B │
    │ 1.2.3.4:12345 198.51.100.1 5.6.7.8:54321│
    │ │ │ │ │
    │ │ 1. Send Indication │ │ │
    │ │ XOR-PEER-ADDRESS: │ │ │
    │ │ 5.6.7.8:54321 │ │ │
    │ │ DATA: "Hello" │ │ │
    │ │ ────────────────────────>│ │ │
    │ │ │ │ │
    │ │ │ 2. 转发数据 │ │
    │ │ │ src: 198.51.100.1:49152 │ │
    │ │ │ dst: 5.6.7.8:54321 │ │
    │ │ │ data: "Hello" │ │
    │ │ │ ────────────────────────────>│ │
    │ │ │ │ │
    │ │ │ 3. 对端响应 │ │
    │ │ │ src: 5.6.7.8:54321 │ │
    │ │ │ dst: 198.51.100.1:49152 │ │
    │ │ │ data: "World" │ │
    │ │ │<──────────────────────────── │ │
    │ │ │ │ │
    │ │ 4. Data Indication │ │ │
    │ │ XOR-PEER-ADDRESS: │ │ │
    │ │ 5.6.7.8:54321 │ │ │
    │ │ DATA: "World" │ │ │
    │ │<──────────────────────── │ │ │
    │ │ │ │ │
    └─────────────────────────────────────────────────────────────────────────┘

    3.2 ChannelData 消息

    使用通道绑定后,可以使用更高效的 ChannelData 消息格式。

    ChannelData 消息格式:

    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
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | Channel Number | Length |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | |
    | Application Data |
    | |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    头部只有 4 字节,比 Send Indication 的 36+ 字节高效得多

    3.3 完整的数据中继流程

    ┌─────────────────────────────────────────────────────────────────────────┐
    │ 完整的 TURN 数据中继流程 │
    ├─────────────────────────────────────────────────────────────────────────┤
    │ │
    │ 客户端 A TURN 服务器 客户端 B │
    │ │ │ │ │
    │ 1. Allocate │ │ │
    │ │ ────────────────────────>│ │ │
    │ │<──────────────────────── │ │ │
    │ │ 中继地址: 198.51.100.1:49152 │ │
    │ │ │ │ │
    │ 2. 通过信令交换中继地址 │ │ │
    │ │ ═══════════════════════════════════════════════════════>│ │
    │ │ │ │ │
    │ 3. CreatePermission │ │ │
    │ │ ────────────────────────>│ │ │
    │ │<──────────────────────── │ │ │
    │ │ │ │ │
    │ 4. ChannelBind (可选) │ │ │
    │ │ ────────────────────────>│ │ │
    │ │<──────────────────────── │ │ │
    │ │ │ │ │
    │ 5. 媒体数据传输 │ │ │
    │ │ ChannelData/Send │ │ │
    │ │ ────────────────────────>│ │ │
    │ │ │ ────────────────────────────>│ │
    │ │ │<──────────────────────────── │ │
    │ │ ChannelData/Data │ │ │
    │ │<──────────────────────── │ │ │
    │ │ │ │ │
    │ 6. 定期 Refresh │ │ │
    │ │ ────────────────────────>│ │ │
    │ │<──────────────────────── │ │ │
    │ │ │ │ │
    └─────────────────────────────────────────────────────────────────────────┘


    4. TURN 认证机制

    4.1 长期凭据机制

    TURN 使用长期凭据 (Long-Term Credential) 进行认证。

    凭据计算:

    key = MD5(username ":" realm ":" password)

    MESSAGE-INTEGRITY = HMAC-SHA1(key, message)

    4.2 认证流程

    ┌─────────────────────────────────────────────────────────────────────────┐
    │ TURN 认证流程 │
    ├─────────────────────────────────────────────────────────────────────────┤
    │ │
    │ 客户端 TURN 服务器 │
    │ │ │ │
    │ │ 1. Allocate Request (无认证) │ │
    │ │ ──────────────────────────────────────────────────> │ │
    │ │ │ │
    │ │ 2. Error Response (401 Unauthorized) │ │
    │ │ REALM: "example.com" │ │
    │ │ NONCE: "abc123…" │ │
    │ │ <────────────────────────────────────────────────── │ │
    │ │ │ │
    │ │ 3. 计算凭据 │ │
    │ │ key = MD5("user:example.com:pass") │ │
    │ │ │ │
    │ │ 4. Allocate Request (带认证) │ │
    │ │ USERNAME: "user" │ │
    │ │ REALM: "example.com" │ │
    │ │ NONCE: "abc123…" │ │
    │ │ MESSAGE-INTEGRITY: HMAC-SHA1(key, msg) │ │
    │ │ ──────────────────────────────────────────────────> │ │
    │ │ │ │
    │ │ 5. 服务器验证 │ │
    │ │ – 检查 USERNAME 是否存在 │ │
    │ │ – 检查 NONCE 是否有效 │ │
    │ │ – 验证 MESSAGE-INTEGRITY │ │
    │ │ │ │
    │ │ 6. Allocate Success Response │ │
    │ │ <────────────────────────────────────────────────── │ │
    │ │ │ │
    └─────────────────────────────────────────────────────────────────────────┘

    4.3 临时凭据 (TURN REST API)

    生产环境通常使用临时凭据,通过 REST API 获取。

    ┌─────────────────────────────────────────────────────────────────────────┐
    │ 临时凭据流程 │
    ├─────────────────────────────────────────────────────────────────────────┤
    │ │
    │ 客户端 应用服务器 TURN 服务器 │
    │ │ │ │ │
    │ │ 1. 请求 TURN 凭据 │ │ │
    │ │ ───────────────────────>│ │ │
    │ │ │ │ │
    │ │ │ 2. 生成临时凭据 │ │
    │ │ │ username = timestamp:userid │ │
    │ │ │ password = HMAC(secret, username) │
    │ │ │ │ │
    │ │ 3. 返回凭据 │ │ │
    │ │ { │ │ │
    │ │ username: "…", │ │ │
    │ │ password: "…", │ │ │
    │ │ ttl: 86400, │ │ │
    │ │ uris: ["turn:…"] │ │ │
    │ │ } │ │ │
    │ │<─────────────────────── │ │ │
    │ │ │ │ │
    │ │ 4. 使用凭据连接 TURN │ │ │
    │ │ ─────────────────────────────────────────────────────>│ │
    │ │ │ │ │
    │ │ │ 5. 验证凭据 │ │
    │ │ │ – 检查时间戳是否过期 │ │
    │ │ │ – 验证 HMAC 签名 │ │
    │ │ │ │ │
    │ │ 6. 连接成功 │ │ │
    │ │<───────────────────────────────────────────────────── │ │
    │ │ │ │ │
    └─────────────────────────────────────────────────────────────────────────┘

    临时凭据生成示例 (Node.js):

    const crypto = require('crypto');

    function generateTurnCredentials(userId, secret, ttl = 86400) {
    const timestamp = Math.floor(Date.now() / 1000) + ttl;
    const username = `${timestamp}:${userId}`;
    const password = crypto
    .createHmac('sha1', secret)
    .update(username)
    .digest('base64');

    return {
    username,
    password,
    ttl,
    uris: [
    'turn:turn.example.com:3478',
    'turn:turn.example.com:3478?transport=tcp',
    'turns:turn.example.com:5349'
    ]
    };
    }

    // 使用示例
    const credentials = generateTurnCredentials('user123', 'my-secret-key');
    console.log(credentials);


    5. coturn 安装与配置

    5.1 安装 coturn

    # Ubuntu/Debian
    sudo apt-get update
    sudo apt-get install coturn

    # CentOS/RHEL
    sudo yum install epel-release
    sudo yum install coturn

    # 从源码编译
    git clone https://github.com/coturn/coturn.git
    cd coturn
    ./configure –prefix=/usr/local
    make
    sudo make install

    5.2 基础配置

    配置文件位置: /etc/turnserver.conf

    # ============ 网络配置 ============

    # 监听端口
    listening-port=3478
    tls-listening-port=5349

    # 监听 IP (0.0.0.0 表示所有接口)
    listening-ip=0.0.0.0

    # 外部 IP (公网 IP)
    external-ip=YOUR_PUBLIC_IP

    # 如果服务器在 NAT 后面
    # external-ip=PUBLIC_IP/PRIVATE_IP

    # 中继端口范围
    min-port=49152
    max-port=65535

    # ============ 认证配置 ============

    # 使用长期凭据机制
    lt-cred-mech

    # 域名
    realm=example.com

    # 静态用户 (测试用)
    user=testuser:testpassword

    # 或使用数据库
    # userdb=/var/lib/turn/turndb

    # ============ 安全配置 ============

    # 指纹验证
    fingerprint

    # 禁止匿名访问
    no-anonymous

    # 禁止回环地址
    no-loopback-peers

    # 禁止多播
    no-multicast-peers

    # ============ TLS 配置 ============

    # 证书文件
    cert=/etc/letsencrypt/live/turn.example.com/fullchain.pem
    pkey=/etc/letsencrypt/live/turn.example.com/privkey.pem

    # 密码套件
    cipher-list="ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"

    # ============ 日志配置 ============

    # 日志文件
    log-file=/var/log/turnserver.log

    # 详细日志
    verbose

    # ============ 其他配置 ============

    # 服务器名称
    server-name=turn.example.com

    # 进程用户
    proc-user=turnserver
    proc-group=turnserver

    # PID 文件
    pidfile=/var/run/turnserver.pid

    5.3 启用服务

    # 编辑 /etc/default/coturn
    sudo sed -i 's/#TURNSERVER_ENABLED=1/TURNSERVER_ENABLED=1/' /etc/default/coturn

    # 启动服务
    sudo systemctl start coturn

    # 设置开机启动
    sudo systemctl enable coturn

    # 查看状态
    sudo systemctl status coturn

    # 查看日志
    sudo tail -f /var/log/turnserver.log

    5.4 防火墙配置

    # UFW (Ubuntu)
    sudo ufw allow 3478/tcp
    sudo ufw allow 3478/udp
    sudo ufw allow 5349/tcp
    sudo ufw allow 5349/udp
    sudo ufw allow 49152:65535/udp

    # firewalld (CentOS)
    sudo firewall-cmd –permanent –add-port=3478/tcp
    sudo firewall-cmd –permanent –add-port=3478/udp
    sudo firewall-cmd –permanent –add-port=5349/tcp
    sudo firewall-cmd –permanent –add-port=5349/udp
    sudo firewall-cmd –permanent –add-port=49152-65535/udp
    sudo firewall-cmd –reload

    # iptables
    sudo iptables -A INPUT -p tcp –dport 3478 -j ACCEPT
    sudo iptables -A INPUT -p udp –dport 3478 -j ACCEPT
    sudo iptables -A INPUT -p tcp –dport 5349 -j ACCEPT
    sudo iptables -A INPUT -p udp –dport 5349 -j ACCEPT
    sudo iptables -A INPUT -p udp –dport 49152:65535 -j ACCEPT

    5.5 测试 TURN 服务器

    使用 turnutils_uclient 测试:

    # 测试 STUN
    turnutils_uclient -t -u testuser -w testpassword turn.example.com

    # 测试 TURN
    turnutils_uclient -T -u testuser -w testpassword turn.example.com

    使用 WebRTC 测试:

    const pc = new RTCPeerConnection({
    iceServers: [{
    urls: [
    'turn:turn.example.com:3478',
    'turn:turn.example.com:3478?transport=tcp'
    ],
    username: 'testuser',
    credential: 'testpassword'
    }]
    });

    pc.createDataChannel('test');

    pc.onicecandidate = (event) => {
    if (event.candidate) {
    console.log('Candidate:', event.candidate.candidate);
    if (event.candidate.candidate.includes('relay')) {
    console.log('TURN relay candidate found!');
    }
    }
    };

    pc.createOffer()
    .then(offer => pc.setLocalDescription(offer));


    6. 生产环境部署

    6.1 高可用架构

    ┌─────────────────────────────────────────────────────────────────────────┐
    │ TURN 高可用架构 │
    ├─────────────────────────────────────────────────────────────────────────┤
    │ │
    │ ┌─────────────────┐ │
    │ │ DNS 负载均衡 │ │
    │ │ turn.example.com │ │
    │ └────────┬────────┘ │
    │ │ │
    │ ┌───────────────────┼───────────────────┐ │
    │ │ │ │ │
    │ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ │
    │ │ TURN 1 │ │ TURN 2 │ │ TURN 3 │ │
    │ │ 区域 A │ │ 区域 B │ │ 区域 C │ │
    │ └────┬────┘ └────┬────┘ └────┬────┘ │
    │ │ │ │ │
    │ └───────────────────┼───────────────────┘ │
    │ │ │
    │ ┌────────┴────────┐ │
    │ │ 共享数据库 │ │
    │ │ (Redis/MySQL) │ │
    │ └─────────────────┘ │
    │ │
    └─────────────────────────────────────────────────────────────────────────┘

    6.2 使用 Redis 存储凭据

    配置 coturn 使用 Redis:

    # /etc/turnserver.conf

    # Redis 配置
    redis-userdb="ip=127.0.0.1 dbname=0 password=redis_password connect_timeout=30"
    redis-statsdb="ip=127.0.0.1 dbname=1 password=redis_password connect_timeout=30"

    添加用户到 Redis:

    # 计算密码哈希
    # key = MD5(username:realm:password)
    echo -n "user1:example.com:password123" | md5sum

    # 添加到 Redis
    redis-cli
    > HSET turn/realm/example.com/user/user1/key "计算出的哈希值"

    6.3 使用 MySQL/PostgreSQL

    # /etc/turnserver.conf

    # MySQL 配置
    mysql-userdb="host=localhost dbname=coturn user=coturn password=db_password"

    # PostgreSQL 配置
    # psql-userdb="host=localhost dbname=coturn user=coturn password=db_password"

    数据库表结构:

    CREATE TABLE turnusers_lt (
    realm VARCHAR(127) DEFAULT 'example.com',
    name VARCHAR(512),
    hmackey CHAR(128),
    PRIMARY KEY (realm, name)
    );

    — 添加用户
    — hmackey = HEX(MD5('username:realm:password'))
    INSERT INTO turnusers_lt (realm, name, hmackey)
    VALUES ('example.com', 'user1', 'a1b2c3d4e5f6…');

    6.4 监控与告警

    # /etc/turnserver.conf

    # 启用 CLI
    cli-ip=127.0.0.1
    cli-port=5766
    cli-password=admin_password

    # Prometheus 指标
    prometheus
    prometheus-port=9641

    使用 CLI 监控:

    # 连接 CLI
    telnet 127.0.0.1 5766

    # 查看会话
    > ps
    > pc

    # 查看统计
    > tc

    Prometheus 指标:

    # HELP turn_total_allocations Total number of allocations
    # TYPE turn_total_allocations counter
    turn_total_allocations 1234

    # HELP turn_active_allocations Current number of active allocations
    # TYPE turn_active_allocations gauge
    turn_active_allocations 56

    6.5 性能优化

    # /etc/turnserver.conf

    # 增加文件描述符限制
    max-bps=0

    # 禁用不需要的功能
    no-cli
    no-rest

    # 优化内存使用
    stale-nonce=600

    # 多进程
    # 根据 CPU 核心数设置
    # 使用 systemd 或 supervisor 管理多个实例

    系统优化:

    # /etc/security/limits.conf
    turnserver soft nofile 65535
    turnserver hard nofile 65535

    # /etc/sysctl.conf
    net.core.rmem_max = 16777216
    net.core.wmem_max = 16777216
    net.ipv4.udp_mem = 8388608 12582912 16777216

    6.6 成本估算

    TURN 服务器的主要成本是带宽:

    假设:
    – 1 路视频通话: 1.5 Mbps (上行 + 下行)
    – 通过 TURN 中继: 带宽翻倍 (3 Mbps)
    – 每天 1000 分钟通话

    月带宽消耗:
    3 Mbps * 60 秒 * 1000 分钟 * 30 天 = 5.4 TB

    按云服务商带宽计费:
    – AWS: 约 $0.09/GB = $486/月
    – 阿里云: 约 $0.12/GB = $648/月

    优化建议:

  • 优先使用 P2P,TURN 作为后备
  • 使用多个区域的 TURN 服务器
  • 监控 TURN 使用率,优化 ICE 配置

  • 7. 总结

    7.1 TURN 核心要点

    要点说明
    作用 P2P 失败时的中继方案
    协议 STUN 的扩展,RFC 5766
    端口 3478 (UDP/TCP), 5349 (TLS)
    认证 长期凭据或临时凭据
    开销 高带宽消耗
    优先级 ICE 中最低优先级

    7.2 部署检查清单

    [ ] 安装 coturn
    [ ] 配置公网 IP
    [ ] 配置 TLS 证书
    [ ] 设置认证机制
    [ ] 开放防火墙端口
    [ ] 测试 STUN 功能
    [ ] 测试 TURN 功能
    [ ] 配置日志和监控
    [ ] 设置自动启动

    7.3 下一篇预告

    在下一篇文章中,我们将完整梳理 WebRTC 的信令流程,从连接建立到关闭的全过程,包括:

    • Offer/Answer 交换
    • ICE Candidate Trickle
    • DTLS 握手
    • SRTP 建立
    • 连接关闭

    参考资料

  • RFC 5766 – Traversal Using Relays around NAT (TURN)
  • RFC 8656 – TURN Extensions
  • coturn – Open Source TURN Server
  • WebRTC TURN – MDN

  • 赞(0)
    未经允许不得转载:171主机测评 » TURN: 中继服务器详解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址