WebRTC DataChannel详解
WebRTC DataChannel详解WebRTC 不只传音视频。DataChannel在同一条 P2P 连接上提供双向任意数据通道聊天、游戏状态、文件分片、协同编辑、控制指令——底层是SCTP over DTLS over UDPRFC 8261。与媒体侧相比载荷与传输语义走 SCTP媒体走RTP/SRTP在BUNDLE下二者仍可能复用同一 UDP 端口与 DTLS 连接只是协议路径不同。和 WebSocket 比它是Peer–Peer可配置可靠/不可靠与有序/无序和完整 libwebrtc 比DataChannel 逻辑可独立学习运行时仍依赖 ICE DTLS。速览定位与 MediaStream 平级的数据通道不经媒体编解码。协议栈应用 →SCTP→DTLS→UDP经 ICE。语义ordered/maxRetransmits/maxPacketLifeTime可控。标识SCTPPPID区分 String/Binary/DCEPStream ID多路复用多个 DataChannel。音视频走RTP/RTCP SRTP不用 SCTP。开源独立实现优先libdatachannelNative ↔ 浏览器互通。核心结论30 秒版DataChannel ≈低延迟 P2P 通用数据管道默认可靠有序可改成「游戏态」不可靠无序。PPID告诉对端负载是字符串还是二进制Stream ID区分多个 channel。媒体与数据共用 ICE常 BUNDLE 同端口数据面 SCTP、媒体面 RTP语义不同。源码里net/dcsctp可单独学产品侧用libdatachannel比抠完整 libwebrtc 更省。大文件必做分片 bufferedAmountLow流控。决策树该不该用 DataChannel需要浏览器/原生之间直接传数据 ├─ 要服务端存、广播、随时断线重连 → WebSocket / 信令服务器 ├─ 要超低延迟 P2P、可牺牲可靠性 → DataChannel不可靠模式 ├─ 要 P2P 文件/聊天、省服务器带宽 → DataChannel可靠模式 └─ 只有音视频 → MediaTrack RTP不必为媒体开 DataChannel 刻意例外用 DataChannel 传业务层同步 / 自定义关键帧请求等 与 RTCP PLI 分离——属高级用法非默认目录1. DataChannel 是什么2. 与 WebSocket 对比3. 协议栈与建连3.3 SDP 中的 SCTP 协商4. 可靠性配置与 API4.3 PR-SCTP 与 FORWARD TSN5. 大文件与流控6. SCTPPPID 与 Stream7. SCTP 协议要点RFC 49608. 音视频为何用 RTP 不用 SCTP9. SCTP 在 WebRTC 之外10. 源码结构与独立学习11. 开源库选型12. 常见坑13. 延伸阅读1. DataChannel 是什么RTCDataChannel让两个对等端在已建立的 RTCPeerConnection上直接交换文本或二进制不经应用服务器中转媒体数据信令仍需服务器交换 SDP/ICE。维度说明模型P2P经 ICE 选路可能经 TURN载荷string/Blob/ArrayBuffer/ TypedArray与媒体关系平级不编码视频帧只传你给的字节加密DTLS数据媒体侧另用 SRTP适合 / 不适合适合不适合实时游戏位置/操作服务端持久存储P2P 文件传输大规模一对多广播本质 1:1 或需 SFU 扩展建连后的聊天 / 业务 RPCNAT 失败且无 TURNCRDT/OT 协同、键鼠控制「随时像 WS 一样重连」的松散会话2. 与 WebSocket 对比特性DataChannelWebSocket连接模型P2PClient–Server延迟通常更低直连经服务器一跳服务器带宽几乎不占数据面高可靠性可选可靠 / 部分可靠 / 不可靠可靠有序性可配置有序部署ICE/STUN/TURN 信令部署简单浏览器需完整 WebRTC 栈极成熟一句话WebSocket 是 C–SDataChannel 是 P2P且传输语义可调。3. 协议栈与建连3.1 数据面协议栈Application (JS / Native DataChannel API) ↓ SCTP多流、消息边界、可选可靠 ↓ DTLS加密与完整性 ↓ UDP经 ICE 选中的候选对媒体面则是编解码 → RTP → SRTP →常经DTLS-SRTP 密钥导出 → UDP。不是「裸 SCTP 塞进 UDP」按RFC 8261SCTP 包封装在DTLS 记录里再走 UDPDTLS 同时承担加密与 ICE 路径上的端口复用。媒体面数据面共用基础设施ICE / STUN / TURNUDPDTLSDataChannel APISCTPMediaTrackRTP / RTCPSRTPBUNDLE 下同一RTCPeerConnection上的 RTP 与 SCTP常常共享一条 ICE 候选对 / 一个 UDP 5-tuple甚至共享 DTLS 握手结果「分家」指的是传输语义与载荷格式不是物理上必有两根网线。3.2 建连顺序简化双方创建RTCPeerConnection发起方createDataChannel(...)须在 offer 前创建SDP 才会出现mapplication交换 Offer/Answer信令交换 ICE CandidateDTLS 握手成功 → SCTP Association 建立DataChannelonopen→send/onmessage接收方通过pc.ondatachannel拿到远端创建的 channel3.3 SDP 中的 SCTP 协商DataChannel 在 SDP 里对应mapplication段SCTP 参数用属性协商不是传统内核 SCTP 监听端口语义SDP 属性作用mapplication … UDP/DTLS/SCTP webrtc-datachannel声明数据通道媒体行asctp-port:port关联内 SCTP 端口号在 DTLS 之上的逻辑端口amax-message-size:n对端愿意接受的最大消息字节数分片上限参考amid:/ BUNDLE 组与音视频 mid 一起做端口复用调试「channel 不 open」时除看 ICE/DTLS还应确认 offer/answer 里是否出现上述行以及max-message-size是否过小导致大消息被拒。4. 可靠性配置与 API4.1 创建参数constdcpc.createDataChannel(chat,{ordered:true,// 是否保序maxRetransmits:10,// 最多重传次数与 maxPacketLifeTime 二选一// maxPacketLifeTime: 3000,});模式配置场景可靠有序默认ordered: true聊天、文件元数据不可靠无序ordered: falsemaxRetransmits: 0游戏高频状态半可靠maxRetransmits: N或maxPacketLifeTime: N实时同步过期丢弃底层对应PR-SCTPRFC 3758。maxRetransmits与maxPacketLifeTime互斥只能设其一。4.2 发送端 / 接收端示例// 发送端constpcnewRTCPeerConnection(config);constdataChannelpc.createDataChannel(chat,{ordered:true});dataChannel.onopen()dataChannel.send(Hello WebRTC!);dataChannel.onmessage(e)console.log(Received:,e.data);// 接收端pc.ondatachannel(event){constdcevent.channel;dc.onmessage(e){dc.send(Echo: e.data);};};send接受string | Blob | ArrayBuffer | ArrayBufferView。4.3 PR-SCTP 与 FORWARD TSN部分可靠不是「UDP 式随手丢」而是发送端在放弃某段数据后用FORWARD TSN或后续扩展通知接收端此前未确认的 TSN 可以跳过别再等重传。JS / API 参数协议侧含义概要maxRetransmits: N某消息重传超过 N 次仍未确认 → 放弃发 FORWARD TSN 推进累积确认点maxPacketLifeTime: N消息在发送队列存活超过 N ms → 放弃同样用 FORWARD TSN 跳过ordered: falseDATA 的 U 标志递交时不按 SSN 排队降低流内等待可靠模式下不会主动 FORWARD 跳过用户数据半可靠/不可靠模式下应用必须能接受丢消息否则应改回默认可靠通道。细节见 RFC 3758 §3–§4。5. 大文件与流控浏览器对单条消息大小有上限常见约16KB256KB量级以实现为准大文件必须分片。constCHUNK_SIZE16*1024;for(leti0;ifile.size;iCHUNK_SIZE){constchunkfile.slice(i,iCHUNK_SIZE);// 配合流控再 send勿无脑循环塞满缓冲区}DataChannel 有发送缓冲发太快会堆积甚至卡住dataChannel.bufferedAmountLowThreshold64*1024;dataChannel.onbufferedamountlow(){sendNextChunk();};用bufferedAmount/onbufferedamountlow不要盲目sleep。bufferedAmount反映的是待发送、已进入 SCTP/发送队列侧的排队字节数实现细节因浏览器而异拷贝、分片、加密前计入时机不完全相同。跨浏览器做流控时阈值宜偏保守阈值略低、chunk 略小并以实测bufferedAmount曲线为准不要假设与某一浏览器完全一致。6. SCTPPPID 与 StreamSCTP 用户数据落在DATA Chunk中。与 DataChannel 最相关的两个字段6.1 PPIDPayload Protocol IdentifierPPID名称含义50WebRTC DCEP通道建立协议OPEN/ACK不暴露给 JS51WebRTC String非空 UTF-8 字符串53WebRTC Binary非空二进制56WebRTC String Empty空字符串SCTP 不允许 0 字节 DATA用 PPID 表示空57WebRTC Binary Empty空二进制发送send(hi)→ 栈填 PPID51send(ArrayBuffer)→ PPID53。接收解 DATA → 读 PPID → 转成 JSString或ArrayBuffer→onmessage。PPID 无法用 JS API 修改由浏览器/原生栈处理见 RFC 8831 / RFC 8832。6.2 Stream Identifier一条SCTP Association通常对应一个 PeerConnection 上的数据关联内可有多条 StreamSCTP Association一条 DTLS 上的关联 ├── Stream ID0 → DataChannel chat (ordered, reliable) ├── Stream ID1 → DataChannel gamePos (unordered, maxRetransmits0) └── Stream ID2 → DataChannel fileXfer (ordered, reliable)每建一个 DataChannel 分配 Stream ID不同 Stream独立排序减轻跨 channel 的队头阻塞收包按 SI 找到 DataChannel → 按 PPID 解析载荷dc.send选 Stream ID 设 PPIDDATA ChunkDTLS对端TSN 重组 → SI → PPIDonmessage7. SCTP 协议要点RFC 4960SCTPStream Control Transmission Protocol是传输层协议RFC 4960。WebRTC 使用SCTP over DTLS over UDPRFC 8261用户态栈历史usrsctpChrome 现多用dcsctp不依赖内核原生 SCTP。一句话SCTP ≈ TCP 的可靠性 UDP 的消息边界/无序可选 多流/部分可靠。7.1 相对 TCP / UDP特性TCPUDPSCTPWebRTC消息边界❌ 字节流✅✅可靠✅❌✅ 可选无序❌✅✅多流❌❌✅部分可靠❌❌✅PR-SCTPNAT友好友好原生不友好 →SCTP/DTLS/UDPRFC 8261TCP 的痛点是字节流有序递交带来的 HOL Blocking一包丢失会堵住后续所有字节。SCTP 用多流做到跨 Stream 互不阻塞但同一 Stream 在ordered: true时丢包仍会造成流内 HOL——只是不会拖死其它 DataChannel。7.2 Common Header Chunk每个 SCTP 包12 字节公共头 一个或多个ChunkTLV。公共头字段作用源/目的端口多路分解Verification Tag关联防注入ChecksumCRC32cRFC 3309常用 ChunkDATA(0)、INIT(1)、INIT ACK(2)、SACK(3)、HEARTBEAT(4/5)、ABORT(6)、SHUTDOWN 系列、COOKIE ECHO/ACK 等。7.3 DATA ChunkTSN 与 SSN 解耦字段作用TSN全局传输序号可靠、重传、去重Stream ID属于哪条流SSN流内序号有序递交U1无序时无效PPID上层协议标识B/E分片首/尾标志TSN 管可靠SSN 管流内有序——这是消除跨流 HOL 的关键。7.4 四路握手 CookieClient --INIT-- Server Client --INIT ACK(Cookie)-- Server Client --COOKIE ECHO-- Server Client --COOKIE ACK-- Server ESTABLISHED服务端收到 INIT不立即建全量 TCB用 Cookie 抗 SYN Flood 类攻击相对 TCP 三路握手。7.5 关闭SCTP不支持 TCP 式半关闭走 SHUTDOWN → SHUTDOWN ACK → SHUTDOWN COMPLETE排空已发数据后再拆关联。7.6 多宿主端点可宣告多 IPPrimary 故障时切 Secondary——电信网常用WebRTC 场景通常单路径多宿主能力用得少。8. 音视频为何用 RTP 不用 SCTP项目音视频DataChannel传输RTP / RTCPSCTP加密SRTPDTLS可靠性偏实时、可丢可选可靠关键语义Timestamp、SSRC、PT消息边界、PPID弱网NACK/FEC/PLI、TWCC/REMBSCTP 自身重传/流控RTPRFC 3550为实时媒体设计宁可丢包不可卡顿时间戳做 A/V 同步序列号做丢包检测RTCP 做质量反馈与拥塞控制。共用ICE UDPBUNDLE 下常复用端口与 DTLS。分家数据面SCTP 消息语义媒体面RTP/SRTP 实时语义——不是两套互不相干的物理链路。9. SCTP 在 WebRTC 之外SCTP 最早服务电信信令不是为浏览器设计的。领域用法SIGTRANSS7 over IPM3UA 等跑在 SCTP 上4G/5GS1-APeNB↔MME、NG-APgNB↔AMF等用 SCTPDiameterAAA 可选 SCTP 传输多宿主高可用互联网家用 NAT/防火墙常不认 IP proto132 → 几乎看不到裸 SCTP因此 WebRTC 采用SCTP over DTLS over UDPRFC 8261而不是在公网上跑裸 SCTP才能穿透 NAT。10. 源码结构与独立学习以 Chromium / webrtc.org 树为例层级路径示意独立性SCTP 栈net/dcsctp/✅ 可单独学、可单测APIapi/data_channel_interface.h✅ 接口清晰通道实现pc/sctp_data_channel.*✅ 状态机桥接pc/sctp_transport.*、dtls_sctp_transport.*⚠️ 粘合 DTLS网络pc/dtls_transport.*、p2p/base/❌ 强依赖 ICE/UDP结论协议与状态机逻辑独立运行时不能像 WebSocket 库一样拔出来裸跑需 mock 网络或走完整 PeerConnection。推荐阅读顺序net/dcsctp/sctp_socket.cc、自带 unit testapi/data_channel_interface.hpc/sctp_data_channel.ccpc/sctp_transport.cc DCEP再碰 DTLS/ICE建立路径概念CreateDataChannel → DCEP OPEN → SctpTransport::SendData → DtlsTransport → IceTransport → UDP反向UDP → ICE → DTLS → dcsctp::ReceivePacket → OnMessage。11. 开源库选型库定位何时选libdatachannel独立 C/C DataChannel 可选媒体 ICE/DTLSNative ↔ 浏览器产品首选usrsctp用户态 SCTP自研栈、嵌 DTLSdcsctpGoogle 现代 SCTPsans-I/O学协议、嵌入自有传输Pion/sctpGoGo 侧 SCTP/DataChannelGo 后端互通aiortcPythonasyncio WebRTC原型、脚本rawrtcdc / librtcdc较轻量 C 实现嵌入式/学习浏览器 WebRTC ├── media (RTP/SRTP) ← 可不用 └── data (SCTP/DTLS/ICE) ← libdatachannel 复刻这条链 ├── usrsctp / dcsctp ├── DTLS └── ICE (libjuice / libnice)产品libdatachannel可NO_MEDIA。啃协议dcsctp 单测 RFC 4960/8261。12. 常见坑现象排查Channel 永不openoffer 前未createDataChannel无mapplicationICE 失败接收方未设ondatachannel对称 NAT 连不上配TURN仅 STUN 不够发文件卡住未做分片 / 未用bufferedAmountLow以为媒体也走 SCTP媒体是RTPchrome://webrtc-internals 分开看关掉泄漏dataChannel.close()pc.close()清引用Safari 行为差异以实测为准能力探测后再开高级选项生产 ICE 示例iceServers:[{urls:stun:stun.l.google.com:19302},{urls:turn:your-turn.example,username:...,credential:...}]调试chrome://webrtc-internals、WiresharkDTLS 解密需密钥日志。13. 延伸阅读资源说明RFC 8831WebRTC Data ChannelsRFC 8832WebRTC Data Channel Establishment ProtocolRFC 4960SCTPRFC 8261SCTP over DTLSRFC 3758PR-SCTP / FORWARD TSNRFC 8843BUNDLE多 m-line 复用RFC 3550RTPMDN RTCDataChannel浏览器 APIdcsctpChromium SCTP 实现libdatachannel独立 DataChannel 库与示例落地时先定语义可靠否、是否保序再定分片与流控NAT 环境默认按「需要 TURN」规划而不是默认「P2P 一定直连成功」。收束DataChannel 用SCTP 的多流 PPID 可选可靠在 P2P 上搬任意字节音视频留给RTP。学协议看dcsctp/RFC做互通产品用libdatachannel二者不要混成一条学习路径。验证环境Chrome / Firefox DataChannel API · RFC 8831/4960/8261 · libdatachannel · webrtc.org dcsctp