# rtp 实时传输协议、RTCP 实时传输控制协议

rtp 是实时传输协议,定义于 rfc3550,是为了需要实时优先级的数据交换提供实时连接。
RTP(实时传输控制协议)负责传媒体,但媒体传的怎么样,就需要 RTCP 来进行反馈和协调,RTCP 专门用户传控制信息、不传音视频数据本身。

# webrtc 网页实时传输协议

webrtc 是网页实时传输协议,是用于客户端点对点建立连接、而不需要服务器中转数据的一种通信方式的协议 webrtc 实际上使用的是 SRTP 协议(安全实时传输协议),确保了交换数据的安全性和身份验证。

# 优势

  1. 跨平台:只要设备的浏览器上支持 webrtc,就可以使用同一套前端代码
  2. 直连成功后可以减少服务器中转和带宽的成本
  3. 低延迟、高吞吐:设备直连时比中转更加直接,但实际效果取决于网络环境
  4. 安全性:传输过程默认加密
  5. 支持 NAT 穿透:ICE 会尝试多种连接路径;直连失败时仍可能需要 TURN 服务器中继

# 浏览器集成

浏览器中已经集成了这样一套完整的 webrtc 的 api,直接使用即可,不过即使这样国内外一些大厂在使用 webrtc 时,常常也不是拿来即用的,而是在 webrtc 的基础之上抽取想要的部分,然后自定义了部分功能。

# webapis

建立 webrtc 连接需要先搭建一个信令服务器,用于连接双方找到彼此。

# RTCPeerConnection

RTCPeerConnection 是核心 api,负责在两个浏览器之间建立、维护、关闭点对点连接,需要传入对应配置,它处理的事情有:

  • SDP 协商
  • fICE 候选收集与交换
  • fNAT 穿透
  • DTLS/SRTPj 加密
  • 音视频编解码协商
  • RTP/RTCPs 媒体传输
  • 带宽估计、连接状态管理

如果仅用于音视频的话,双方的 connection 实例中监听 ontrack 就能收到音视频流了,但是如果还要传输自定义数据的话,就需要使用 RTCDataChannel 了。

# RTCDataChannel

RTCDataChannel 的作用是在已建立的 RTCPeerConnection 之上,创建一个双向数据通道,用于传输文本、二进制、文件、游戏指令等任意的数据

  • RTCDataChannel 类似于 websocket,但它是点对点的
  • 可以进行配置:可靠 / 不可靠、有序 / 无序
  • 适合聊天、文件传输、实时游戏状态同步、元数据交换 等

# 信令交换与 NAT 穿透

信令服务器用于进行 “信息交换和协调会话 “,NAT 穿透负责 “打洞直连、中继兜底 “,两者配合,WebRTC 才能即找到对方又真正直连。

# 领域知识

# 信令

信令是双方建立连接所需要的信息,由于通信过程中需要双方双向通信、且服务端要能主动推送,所以通常使用 websocket 实现。

# 信令服务器

# 为什么使用 websocket 协议

在连接建立和连接状态变化阶段,信令服务器需要服务端频繁推送消息给客户端,而客户端也得主动发送消息给信令服务器,这种全双工的通信协议非常适合使用 websocket 去实现。

# 信令为什么频繁交换

信令交换不是一次性的,WebRTC 使用 SDP 来描述:“我支持什么编解码、什么媒体、什么网络地址 “。连接流程是:

sequenceDiagram
    autonumber
    participant A as Peer A(主叫)
    participant S as 信令服务器
    participant B as Peer B(被叫)
    participant ICE as STUN/TURN 服务器
    Note over A: 创建 RTCPeerConnection<br/>添加媒体轨道或 DataChannel
    A->>A: createOffer()
    A->>A: setLocalDescription(offer)
    A->>S: 发送 SDP Offer
    S->>B: 转发 SDP Offer
    B->>B: setRemoteDescription(offer)
    B->>B: createAnswer()
    B->>B: setLocalDescription(answer)
    B->>S: 发送 SDP Answer
    S->>A: 转发 SDP Answer
    A->>A: setRemoteDescription(answer)
    par Peer A 收集 ICE Candidate
        A->>ICE: STUN Binding / TURN Allocate
        ICE-->>A: 返回候选地址
        A->>S: 发送 ICE Candidate
        S->>B: 转发 ICE Candidate
    and Peer B 收集 ICE Candidate
        B->>ICE: STUN Binding / TURN Allocate
        ICE-->>B: 返回候选地址
        B->>S: 发送 ICE Candidate
        S->>A: 转发 ICE Candidate
    end
    Note over A,B: ICE 连通性检查,选择最优候选对<br/>可能是直连,也可能经 TURN 中继
    A->>B: STUN Binding Request
    B-->>A: STUN Binding Success
    B->>A: STUN Binding Request
    A-->>B: STUN Binding Success
    Note over A,B: 在选定的候选对上执行 DTLS 握手
    A->>B: DTLS ClientHello
    B-->>A: DTLS ServerHello / Certificate / KeyExchange
    A->>B: DTLS Finished
    B-->>A: DTLS Finished
    alt 媒体通信
        Note over A,B: 从 DTLS 导出 SRTP 密钥
        A-->>B: SRTP/RTP 媒体流
        B-->>A: SRTP/RTP 媒体流
    else DataChannel 通信
        Note over A,B: 在 DTLS 上建立 SCTP 关联
        A-->>B: SCTP/DataChannel 数据
        B-->>A: SCTP/DataChannel 数据
    end
    Note over A,B: ICE/DTLS 完成,连接状态 connected

这种连接过程至少是一来一回的方式,但实际过程中还可能会发生:

  1. 新增 / 删除音视频轨道
  2. 屏幕共享的开始 / 结束
  3. 修改音视频编解码、带宽、方向等
  4. 网络变化导致 ICE 重新选举
  5. 连接失败时重新协商

这每一次的处理过程都需要重新 offer/answer、都需要信令服务器重新转发各种信令消息,所以信令不是一次性的、而是需要频繁交换。

# SDP 会话描述协议

SDP 不传媒体或者数据,只描述媒体 / 数据怎么传,是描述格式 / 协商载体,不是媒体传输协议。

# NAT 网络地址转换

NAT 网络地址转换的作用是:在 IP 数据包经过网络设备(路由器或防火墙)时,修改源 IP、目的 IP、源端口、目的端口的机制。

# 举例

  1. NAT 最常见的作用是让多个内网设备共享一个公网 IP 上网:
  • 当内网设备访问外部服务器时,路由器会使用 NAT 将 IP 包的源 IP 地址修改为自己公网 IP 的地址
  • 外部服务器看到的源 IP 地址是公网 ip 的,而不是内网 ip 地址
  • 返回数据到达时,路由器再根据 ip 映射表将目标 ip 地址修改为对应内网 ip

# 作用

  1. 缓解 IPv4 地址枯竭
    公网 IPv4 地址有限,NAT 让成百上千台内网设备共享少量公网 IP。
  2. 内网地址复用
    不同内网可以重复使用 192.168.x.x、10.x.x.x 等私有地址,互不冲突。
  3. 隐藏内网结构
    外网只能看到 NAT 设备的公网地址,看不到内网设备的真实 IP 和拓扑。
  4. 提供一定安全隔离
    默认情况下,外网不能主动访问内网设备,除非 NAT 上配置了端口映射。
    但 NAT 不等于防火墙,它只是附带了一定的隔离效果。
  5. 简化网络管理
    企业、家庭网络不需要给每台设备分配公网 IP,出口统一做转换即可。

# 缺点

NAT 网络地址转换让多个内网设备共享了一个公网 IP,同时带来了后果:

  1. 外网不能主动访问内网设备,除非 NAT 上有明确的端口映射。

# 内网穿透与 NAT 穿透

NAT 穿透是内网穿透的一种,内网穿透的范围更广:

  • 内网穿透的重点是让外部能够访问到内网服务,或者让内网之间互通
  • NAT 穿透的重点是让两个都在 NAT 后面的设备直接互通、优先打洞直连

# NAT 穿透的具体实现

NAT 穿透常见的技术实现有:STUN、UDP 打洞、TCP 打洞、TURN、ICE 等。

# STUN(NAT 会话穿越工具)

STUN 作用是:帮助客户端发现自己的公网地址,尝试直连。因为 NAT 会将内网地址转换成公网地址,所以客户端不知道自己在公网上的地址是什么,而 STUN 的作用是将 NAT 分配的公网映射告诉自己。

# 工作方式

  1. 客户端向 STUN 服务器发送一个 Binding 请求。
  2. STUN 服务器收到后,把看到的源 IP 和端口返回给客户端。
  3. 客户端得到自己的公网映射地址。
  4. 这个地址作为 ICE 候选之一,参与连通性检查。
sequenceDiagram
    participant C as 客户端<br/>内网 192.168.1.10:54321
    participant N as NAT
    participant S as STUN 服务器<br/>公网
    C->>N: 1. 发送 STUN Binding Request<br/>源地址:192.168.1.10:54321
    N->>S: 2. 转发请求<br/>NAT 将源地址改为公网地址 xxxx:80304
    Note over S: 3. STUN 服务器看到源地址<br/>xxxx:80304
    S->>N: 4. 返回 Binding Response<br/>包含 XOR-MAPPED-ADDRESS = xxxx:80304
    N->>C: 5. 转发响应
    Note over C: 6. 客户端得到自己的公网映射地址<br/>作为 srflx 候选

# UDP 打洞

当使用 STUN(NAT 会话穿越工具)获取到在公网地址的映射时,就需要发送 STUN 请求去进行 UDP 打洞、在各自的 NAT 上打开临时通道、建立一条连接,流程如下:

sequenceDiagram
    participant A as Peer A
    participant NATA as NAT A
    participant NATB as NAT B
    participant B as Peer B
    Note over A,B: 前置:通过信令交换 SDP 和 ICE 候选
    Note over A,B: 双方各自获得 host / srflx / relay 候选
    Note over A,B: 假设双方选择 srflx 候选进行直连尝试
    A->>NATA: 发送 STUN 请求到 B 的公网地址
    NATA->>NATB: 出站包,NAT A 创建映射
    NATB->>B: 转发到 B
    B->>NATB: 发送 STUN 请求到 A 的公网地址
    NATB->>NATA: 出站包,NAT B 创建映射
    NATA->>A: 转发到 A
    B-->>A: STUN 响应
    A-->>B: STUN 响应
    Note over A,B: 双方 NAT 都允许对方入站,打洞成功
    A->>B: DTLS 握手
    B->>A: DTLS 握手
    Note over A,B: 密钥协商完成
    A->>B: SRTP / SRTCP 媒体流
    B->>A: SRTP / SRTCP 媒体流
    Note over A,B: 直连建立,媒体不经过服务器

常见的打洞失败的原因:

  1. 对称 NAT
  2. 端口受限 NAT
  3. 运营商 NAt
  4. 防火墙阻止 UDP、阻止入站包
  5. IP 版本不匹配
  6. 浏览器权限或者系统权限不足 等

UDP 打洞依赖于 NAT 在分配和映射公网端口时,对端口映射的维护(一段时间没流量就会删除映射)。
打洞的过程是双向的,双方都会向对方的候选地址发送 STUN Binding 请求,因为内网主动向外发送发包,NAT 才会建立映射、之后来自那个目标地址的回包,NAT 才允许进入。

# TURN(使用中继穿越 NAT)

TURN 的作用是:当双方无法直连时,RURN 服务器作为中继,转发双方的音视频和数据,它充当一个 “中间人 “,所有媒体先发送给 TURN,再由 TURN 转发给对方。

# 工作方式

  1. 客户端向 TURN 服务器申请分配一个中继地址。
  2. TURN 服务器分配一个公网地址和端口,比如 198.51.100.7:60000。
  3. 客户端把这个地址作为 relay 候选,通过信令发给对方。
  4. 对方把媒体发到这个地址,TURN 服务器再转发给客户端。
  5. 反向同理。
sequenceDiagram
    participant A as 客户端 A
    participant T as TURN 服务器
    participant B as 客户端 B
    Note over A,T: 阶段一:A 向 TURN 申请中继地址
    A->>T: 1. Allocate 请求(认证)
    T-->>A: 2. 分配成功,返回 A 的中继地址<br/>Relay-A = 198.51.100.7:60000
    Note over B,T: 阶段二:B 向 TURN 申请中继地址
    B->>T: 3. Allocate 请求(认证)
    T-->>B: 4. 分配成功,返回 B 的中继地址<br/>Relay-B = 198.51.100.7:60001
    Note over A,B: 阶段三:通过信令交换中继地址
    A->>B: 5. 信令:A 告诉 B 自己的中继地址 Relay-A
    B->>A: 6. 信令:B 告诉 A 自己的中继地址 Relay-B
    Note over A,T: 阶段四:A 向 B 发送数据(媒体或 DataChannel)
    A->>T: 7. CreatePermission 请求<br/>允许 B 的地址
    T-->>A: 8. 权限创建成功
    A->>T: 9. Send Indication / ChannelData<br/>目标:Relay-B,负载:媒体数据
    T->>B: 10. 通过 B 与 TURN 的连接转发数据
    Note over B,T: 阶段五:B 向 A 发送数据
    B->>T: 11. CreatePermission 请求<br/>允许 A 的地址
    T-->>B: 12. 权限创建成功
    B->>T: 13. Send Indication / ChannelData<br/>目标:Relay-A,负载:媒体数据
    T->>A: 14. 通过 A 与 TURN 的连接转发数据
    Note over A,B: 后续媒体流持续通过 TURN 中继

# ICE 候选

连接 P2P 连接的条件是:双方需要知道对方、以及自己公网上的可达地址;ICE 候选机制就是一套 “收集所有可能地址、交换、逐一验证、选最优路径 “的机制。
ICE 候选的过程

  1. NAT(网络地址转换)穿透
  2. 防火墙穿透
  3. 中继兜底
  4. 多路径选择
  5. 适应网络变化
  6. 为 DTLS/SRTP 提供传输通道

# 什么是 ICE 候选

一个 ICE 候选就是一个 “可能可用的传输地址 “,通常包含:

  • IP 地址
  • 端口
  • 传输协议
  • 候选类型(host 本机网卡、srflx STUN 服务器的反射、prflx 连通性检查中发现、relay TURN 服务器分配)
  • 优先级
  • 基础地址 等

在 ICE 候选过程中,因为网络路径不稳定,所以 A 和 B 之间各自收集到多个候选:

  • 本地局域网地址
  • 公网反射地址
  • TURN 中继地址

这些地址两两组合,会形成很多个 “候选对 “,ICE 候选要找出最优的网络联通方式

flowchart TD
    A[开始收集] --> B[host 候选<br/>本机网卡地址]
    A --> C[向 STUN 请求]
    C --> D[srflx 候选<br/>NAT 公网映射]
    A --> E[向 TURN 申请]
    E --> F[relay 候选<br/>TURN 中继地址]
    B & D & F --> G[通过信令交换]
    G --> H[形成候选对]
    H --> I[连通性检查]
    I --> J{是否成功?}
    J -- 是 --> K[提名并选中]
    J -- 否 --> L[尝试下一候选对]
    L --> I
    K --> M[媒体传输]

# 直连遇到的问题

假设 A 和 B 想直连。最理想是 A 知道 B 的 IP: 端口,B 知道 A 的 IP: 端口,然后直接发 UDP。
但现实是:

  • A 可能在 NAT 后面,本地地址是 192.168.1.2:5000,公网映射可能是 203.0.113.5:62000。
  • B 也在另一个 NAT 后面。
  • 双方都不知道自己的公网映射,更不知道对方的。
  • 防火墙可能只允许某些方向、某些端口。
  • 设备可能有 Wi-Fi、有线、4G 多个网卡,有多个本地地址。
  • 对称 NAT 下,映射还会随目标变化。
  • 所以只交换一个地址几乎必然失败。ICE 候选机制就是为了解决 “到底用哪个地址才能连通” 的问题。

# DTLS/SRTP 加密

DTLS(数据报传输层安全)可以看成是跑在 UDP 协议上的 TLS 安全层协议;SRTP(安全实时传输协议)是 RTP 的加密版本

# 音视频编解码加密

# 带宽估计、连接状态管理

更新于 阅读次数 次

请我喝[茶]~( ̄▽ ̄)~*

dmq 微信支付

微信支付

dmq 支付宝

支付宝