【ZeroRange WebRTC】WebRTC 基于 STUN 的 srflx 直连原理与实现

WebRTC 基于 STUN 的 srflx 直连原理与实现

本文系统梳理在手机 App 与 IPC 设备之间,基于 STUN 获取到 srflx(Server Reflexive)候选后如何实现点对点直连进行音视频传输的完整技术路径,包括 NAT 出站映射、ICE 连通性检查、候选选择与提名、DTLS-SRTP 加密、保活与 Consent Freshness 等关键机制,并结合 Amazon Kinesis WebRTC C SDK 的落地细节与排错要点。


1. 核心概念

  • srflx 候选:通过向公网 STUN 服务器发送 Binding Request 后,服务器在响应中返回请求的源地址(XOR-MAPPED-ADDRESS),即"外界看到的你的公网 IP:端口"。这对应 NAT 为该本地 socket 建立的出站映射。
  • 5‑tuple:唯一标识一条传输层流的五元组:源IP源端口目的IP目的端口协议(UDP/TCP)。NAT/防火墙/内核 conntrack 都按 5‑tuple 维护状态。
  • ICE 候选类型与优先:一般优先级 host > srflx > relay(TURN);ICE 通过对"本地候选 ↔ 远端候选"进行 STUN 连通性检查,选出最优且可达的候选对。
  • NAT 出站映射:当内网端向外发 UDP 包时,NAT 为 内网IP:内端口 分配一个 公网IP:外端口 并建立转换表项与过滤规则;不同 NAT 类型(全锥/受限锥/端口受限锥/对称)对入站放行的条件不同。

参考:RFC 5389(STUN)、RFC 8445(ICE)、RFC 5766(TURN)。


2. 形成直连的完整过程

  1. 信令交换(WSS/HTTPS):双方通过信令通道交换 SDP(编解码、指纹、a=setup 等)以及 Trickle ICE 候选。
  2. 收集 srflx:每端向 STUN 发送 Binding Request,NAT 建立出站映射,STUN 在 Binding Success Response 中返回 XOR-MAPPED-ADDRESS,形成 srflx 候选。
  3. 传播候选:双方将 host/srflx/(必要时)relay 候选通过信令发送给对端。
  4. 连通性检查(双向):每端用自己的本地候选对远端候选发 STUN 检查。双向检查满足受限锥/端口受限锥 NAT 的"我曾向你发过包"过滤条件。
  5. 候选对通过:某个候选对检查成功,双方 NAT 都建立并允许该 5‑tuple 的入站/出站,路径打通。
  6. 提名与固定:ICE controlling 端发送 USE-CANDIDATE 提名该候选对,controlled 端确认后固定此 5‑tuple 为媒体路径。
  7. DTLS 握手与 SRTP:在固定的 5‑tuple 上完成 DTLS 握手(角色由 SDP a=setup 协商),导出 SRTP 密钥(RFC 5764),后续用 SRTP 加密 RTP/RTCP。
  8. 直接传输媒体:音视频 RTP/RTCP 包沿该 5‑tuple 点对点传输,通常无需经任何服务器中继。

3. NAT 打洞的技术细节

  • 出站映射与端口复用:ICE 复用同一个本地 socket/端口向 STUN 与对端发包,确保继续使用已在 NAT 上建立的映射,避免新端口导致重新建映射。
  • NAT 过滤策略:
    • 全锥:任何对端都可向"映射的公网端口"入站。
    • 受限锥:仅允许"我曾向其发过包的对端 IP"入站。
    • 端口受限锥:进一步受限到"IP+端口"。
    • 对称 NAT:外部端口与目标地址绑定,给 STUN 的映射对其他对端不可用,srflx 直连常失败。
  • 映射闲置超时:NAT 对 UDP 映射设定超时(常见 30--120 秒),若无流量则清除;需保活维持。
  • prflx 候选:检查过程中可能出现对端未声明但可达的本地地址,形成 peer reflexive 候选,并可能被选中。

4. 候选选择与提名(ICE 角色)

  • 角色划分:ICE 有 controlling/controlled 两个逻辑角色,仅影响提名流程;两端都会并行发 STUN 检查。
  • 提名:controlling 端在某个候选对通后发送 USE-CANDIDATE 属性提名,controlled 端确认后固定路径。
  • 路径复用:提名后的所有流量(STUN 保活与 consent、DTLS、RTP/RTCP、SCTP 数据通道)均复用同一 5‑tuple,保证 NAT 状态一致与稳定。

  • 保活(Keepalive):周期发送小报文维持 NAT 映射不超时。常用 STUN Binding Indication(不需要响应,轻量),或小体积 RTCP/RTP 心跳。典型间隔 15--20 秒以适配保守 NAT。
  • Consent Freshness(同意新鲜度):周期性在"已选候选对"的 5‑tuple 上发送 STUN Binding Request,要求对端返回成功响应并校验 MESSAGE-INTEGRITY(基于 ice-pwd)。若在规定窗口内未获得响应(例如连续失败或超过约 30 秒),必须停止在该 5‑tuple 上发送媒体,避免向无效或非同意的地址持续发流量。参考 RFC 7675。
  • 二者差异:保活可用不需响应的 Indication,只维持映射;Consent Freshness需可验证的响应,确保对端仍"同意"接收。

6. 安全与加密

  • DTLS 握手:在选定 5‑tuple 上进行 DTLS 握手,角色由 SDP a=setup(如 actpass/active/passive)协商。证书指纹在 SDP 中交换防止中间人攻击。
  • SRTP:DTLS 握手后按照 RFC 5764 导出 SRTP 密钥,后续 RTP/RTCP 全程加密与鉴别。
  • STUN 完整性:STSUN 请求/响应带 MESSAGE-INTEGRITYFINGERPRINT,防止伪造与损坏。

7. 何时需要 TURN 回落

  • 对称 NAT:srflx 通常不可用;需使用 TURN relay 候选。
  • UDP 被阻断或强审计:企业网络/移动网络可能限制 UDP;TURN 可走 TCP 或 TLS(turns)。
  • 防火墙策略:目的端口或外联受限导致检查失败;允许 TURN 中继可显著提高成功率。

8. 在 Amazon Kinesis WebRTC C SDK 中的对应

  • 端点发现:先通过 HTTPS 端点获取 STUN/TURN 配置(GetIceServerConfig),通过 WSS 建立信令。你可能在日志中看到形如:{"ResourceEndpointList":[{"Protocol":"HTTPS"...},{"Protocol":"WSS"...}]}
  • ICE 收集与检查:ICE 模块向 STUN 发 Binding Request 生成 srflx,随后对候选对做连通性检查。
  • 候选选择与媒体:日志会打印"selected candidate pair"的类型(host/srflx/relay)。选中 srflx 即为直连;之后完成 DTLS→SRTP,在该 5‑tuple 上传输媒体。
  • 状态机位置:信令状态推进逻辑位于 src/source/Signaling/StateMachine.c(如 SIGNALING_STATE_NONE 为起始/占位),具体 ICE/DTLS/RTP 模块位于 src/source/Ice/, Rtp/, Srtp/, PeerConnection/ 等目录。

9. 日志定位与排错清单

  • 关注关键词:GetIceServerConfigOnIceCandidateConnectivity checkselected candidate pairUSE-CANDIDATEDTLS handshakeSRTP establishedBinding Indication/Request
  • 常见问题:
    • WSS 握手失败:检查系统时间、根证书、代理/防火墙。
    • GetIceServerConfig 403:核查 IAM 权限与区域/通道 ARN。
    • 连通性检查失败:可能为对称 NAT 或 UDP 阻断;启用 TURN 并允许 TCP/TLS。
    • 映射超时掉线:增大保活频率(15--20 秒),确保 Consent Freshness 响应正常。
    • 编解码/带宽问题:检查 RTP/RTCP 反馈(PLI/NACK/TCC/REMB),适配码率与抖动缓冲。

10. FAQ(角色与连接)

  • 谁是"客户端/服务端"?在 UDP 传输层,两端都是对等体;只有 ICE(controlling/controlled)与 DTLS(握手的 client/server)存在逻辑角色。
  • 为何必须"双向检查"?受限锥/端口受限锥 NAT 要求"我曾向该对端发过包"才放行入站;双向 STUN 检查满足双方 NAT 的过滤条件。
  • 5‑tuple 为什么重要?它是 NAT/防火墙的状态键;提名后复用同一 5‑tuple 能保证 DTLS/SRTP/STUN 与媒体路径一致、稳定。

11. 一个简化的时序示例

  • IPC:192.168.1.10:5000 → STUN(UDP)→ NAT 建映射 203.0.113.5:62000 → 获得 srflx
  • 手机:10.0.0.7:4000 → STUN(UDP)→ NAT 建映射 198.51.100.7:55000 → 获得 srflx
  • 互发检查:手机向 203.0.113.5:62000 发 STUN;IPC 向 198.51.100.7:55000 发 STUN → 双侧 NAT 放行。
  • 提名与固定:ICE 选中并提名该候选对 → 在此 5‑tuple 上完成 DTLS → 导出 SRTP → 媒体直连传输。

12. 进一步参考

  • RFC 5389: Session Traversal Utilities for NAT (STUN)
  • RFC 8445: Interactive Connectivity Establishment (ICE)
  • RFC 5766: Traversal Using Relays around NAT (TURN)
  • RFC 5764: SRTP Keying via DTLS-SRTP
  • RFC 7675: STUN Usage for Consent Freshness
  • 本仓库文档:docs/ice-srflx-connectivity.zh.mddocs/https-wss-webrtc.zh.mddocs/webrtc-ice-paths.svg

若你需要将具体运行日志(如"selected candidate pair"的类型、Consent 检查的响应情况)映射到上述步骤,我可以继续按日志时间线为你标注与定位。


13. 技术原理补充(更深入)

  • NAT 转换表项与出站映射:当内网端(如 IPC 或手机)发出 UDP 报文时,NAT 会为该本地 5‑tuple 建立一条"转换/过滤"状态,并分配一个外网端口。典型形态:(内网IP, 内端口, 协议[, 目标IP/端口约束]) → (公网IP, 外端口),并带有闲置超时(常见 30--120 秒)。
  • STUN XOR-MAPPED-ADDRESS:向公网 STUN 发送 Binding Request 后,服务器在成功响应中回显"请求的源地址",这就是你的 srflx 公网地址,直接对应 NAT 刚建立的出站映射。
  • 对称 NAT 的限制:对称 NAT 的映射与"目标地址"绑定,给 STUN 建的外网端口仅对 STUN 目的地址有效,换到对端地址时会使用不同外网端口,导致 srflx 直连常失败,需要回落到 TURN。
  • 双向检查的必要性:受限锥/端口受限锥 NAT 会要求"我曾向该对端(IP/端口)发过包"才放行入站。因此 ICE 需要双方都向对端候选发 STUN 检查,才能同时满足两侧 NAT 的过滤条件。
  • Binding Request vs Binding Indication
    • Request 需要对端响应,用于连通性检查与 Consent Freshness(确认对端仍"同意"接收)。
    • Indication 不需要响应,负载更轻,常用于保活以维持 NAT 映射不过期。
  • 5‑tuple 复用:提名后将 STUN/DTLS/RTP/RTCP/SCTP 全部复用同一 5‑tuple,保证 NAT 状态一致、握手与媒体路径不脱节;若 5‑tuple 变化(如端口或网络切换),需重新检查或 ICE 重启。

14. SDK 实现位置与关键函数(Amazon Kinesis WebRTC C SDK)

  • 收集与初始化 srflx
    • src/source/Ice/IceAgent.c 中的 iceAgentInitSrflxCandidateiceAgentSendSrflxCandidateRequest 负责初始化与向 STUN 发送请求以生成 srflx 候选。
    • STUN 成功响应处理(STUN_PACKET_TYPE_BINDING_RESPONSE_SUCCESS)中包含识别 srflx 的逻辑与诊断更新(同文件)。
  • 连通性检查与提名:
    • 候选对状态与"提名"标志 nominated 的维护在 IceAgent.csrc/source/Ice/IceAgentStateMachine.c(状态 ICE_AGENT_STATE_NOMINATING)。
    • 一旦找到"已提名且检查成功"的候选对,会将其设置为数据发送对(pDataSendingIceCandidatePair)。
  • 保活与 Consent:
    • src/source/Ice/IceAgent.ciceAgentSendKeepAliveTimerCallback 配合定时器在已选候选对上发送保活(日志中常见 Received STUN binding indication)。
    • 统计结构中包含"用于验证 consent 的请求往返"指标,见 src/include/com/amazonaws/kinesis/video/webrtcclient/Stats.hsrc/source/Metrics/Metrics.cgetIceCandidatePairStats
  • SDP 与候选类型:src/source/Sdp/Sdp.h 定义 SDP_CANDIDATE_TYPE_SERFLX"srflx")。
  • 入口与回调:src/source/PeerConnection/PeerConnection.c 负责创建 ICE Agent 与注册回调(如 onIceConnectionStateChangeonNewIceLocalCandidate)。
  • 样例与测试:
    • 测试:tst/PeerConnectionFunctionalityTest.cpp 中的 connectTwoPeersWithHostAndStun 验证主机与 STUN 候选可连接;multipleCandidateSuccessOneDTLSCheck 验证 DTLS 仅在选定对上进行一次。
    • 样例:samples/Common.c 展示配置 STUN/TURN 与初始化 PeerConnection 的流程。

15. 调试日志样例与关键词对照

  • 端点发现(信令):
    • Received client http read response: {"ResourceEndpointList":[{"Protocol":"HTTPS"...},{"Protocol":"WSS"...}]}
  • 收集与检查:
    • new local candidate: type=srflx ...(不同日志级别实现可能有差)
    • Connectivity check successSelected candidate pair: local=..., remote=..., type=srflx(或 host/relay
  • 提名与固定:
    • nominated=trueICE_AGENT_STATE_NOMINATING → READY(状态机推进)
  • 保活与 Consent:
    • Received STUN binding indication(保活)
    • Binding Request 成功/失败与往返统计(Consent Freshness)
  • 安全与媒体:
    • DTLS handshake completeSRTP established、随后开始 RTP/RTCP 传输。

16. srflx 直连 Checklist(实践建议)

  • STUN 可达:确保公网 STUN 服务器可访问,DNS/TLS(若走 turns/wss)与路由正常。
  • UDP 放行:运营商/企业网络允许 UDP;若受限,配置 TURN 并允许 TCP/TLS 中继。
  • NAT 友好:对称 NAT 环境预置 TURN;优先使用 Trickle ICE,延长候选收集时间以提高直连概率。
  • 同一 socket 复用:确保实现复用同一本地端口进行 STUN 与检查,避免端口切换导致映射重建。
  • 保活频率:设置保守的保活间隔(15--20 秒);监控 Consent Freshness 响应,超时即停发并重试/重选候选。
  • 编解码与拥塞:关注 RTCP/TCC/REMB/NACK/PLI 指标,合理配置码率与抖动缓冲以保障体验。

17. 术语速查

  • srflx:Server Reflexive 候选,来自 STUN 响应的公网映射地址。
  • prflx:Peer Reflexive 候选,检查中发现的对端可达本地地址。
  • nominated:被 controlling 端提名且检查成功的候选对标志。
  • 5‑tuple:源IP/源端口/目的IP/目的端口/协议,网络状态的唯一键。
  • Consent Freshness:通过需响应的 STUN Binding Request 周期确认对端仍"同意"接收。
相关推荐
小柯博客2 小时前
STM32MP1 没有硬件编解码,如何用 CPU 实现 H.264 编码支持 WebRTC?
c语言·stm32·嵌入式硬件·webrtc·h.264·h264·v4l2
RTC老炮11 小时前
webrtc降噪-PriorSignalModelEstimator类源码分析与算法原理
算法·webrtc
卜锦元17 小时前
Mediasoup的SFU媒体服务转发中心详解(与传统SFU的区别)
音视频·webrtc·媒体
pp-周子晗(努力赶上课程进度版)17 小时前
Node.js 模块系统选择-学习 CommonJS 和 ESM
node.js·webrtc
赖small强2 天前
【ZeroRange WebRTC】NAT 与防火墙在 WebRTC 中的影响
webrtc·防火墙·nat·stun
赖small强2 天前
【ZeroRange WebRTC】OpenSSL 与 WebRTC:原理、集成与实践指南
webrtc·openssl·x.509·证书验证·tls/dtls
赖small强2 天前
【ZeroRange WebRTC】WebRTC 媒体安全:实现原理与应用(深入指南)
webrtc·dtls-srtp·端到端加密·srtcp 控制安全·srtp 加密与完整性
赖small强3 天前
【ZeroRange WebRTC】码学基础与实践:哈希、HMAC、AES、RSA/ECDSA、随机数、X.509
webrtc·哈希算法·aes·hmac·rsa/ecdsa·x.509
小柯博客4 天前
交叉编译aws kvs webrtc
webrtc