DataChannel 优化
DataChannel 实现DataChannel 的实现有两种webrtc 目前使用自行基于 C 开发的 dcsctpmediasoup 和 libdatachannel 基于 usrsctpusrsctp 为开源 sctp 协议实现均遵守 rfc 4960 标准。RFCRFC 4960 - Stream Control Transmission Protocol能力概述DataChannel (sctp支持可靠传输、不可靠传输两种模式其中不可靠传输有两种方式一种基于配置包最大生命周期进行配置另一种是基于最大重传次数进行配置。如若使用可靠传输只需将Client 端的 reliable 配置为 true 即可server 的 usrsctp 中的 spa.sendv_prinfo.pr_policy 配置为 SCTP_PR_SCTP_NONE 即可如若需要使用不可靠传输模式则分以下两种方式基于生存时间和重传次数二者只能选其一基于最大生命周期 maxRetransTime 为数据报在 sctp 队列中最大存活时间该参数可以保证发送队列可以快速的情况尽量降低后续包发送失败的概率但是存在在网络拥塞的情况下因 CC 控制导致数据报尚未发送便被清理的问题即数据包没有经过一次发送便因超时而被清理了。基于最大重传次数 maxRetrans 为数据报在发送队列中最多重传的次数可保证数据至少在网络中发送一次但如若出现了网络丢包不会进行重传注意在 usrsctp 中此参数至少要配置为 1 才能保证至少发送一次与 client 不同。性能两者默认都较弱不论是其可靠传输还是不可靠传输抗弱网能力均较弱但测试下来 usrsctp 比 dcsctp 要强一些不过 usrsctp 基于 c 开发代码缩写、简写严重难以阅读理解而 dcsctp 基于 C 实现相对要容易理解一些弱网性能在可靠传输模式下30% 的丢包即为上限还不如 tcp具体数据暂不列了更高的丢包率测试无法进行下去。原因分析发送窗口sctp 在拥塞控制算法上与 tcp 类似分为慢启动、拥塞避免、快速恢复 和快速重传几个阶段。在出现弱网即出现 丢包 或者 重传超时的情况时发送窗口 cwnd 和 慢启动阈值 ssthresh 减半过快其 cwnd 最低值过低首先从这一点进行入手分析。以下 Url 是 RFC 中对 CWnd 和 SStreash 的配置策略https://datatracker.ietf.org/doc/html/rfc4960#section-6.3.3https://datatracker.ietf.org/doc/html/rfc4960#section-7.2.3原文如下7.2.3. Congestion Control Upon detection of packet losses from SACK (see Section 7.2.4), an endpoint should do the following: ssthresh max(cwnd/2, 4*MTU) cwnd ssthresh partial_bytes_acked 0 Basically, a packet loss causes cwnd to be cut in half. When the T3-rtx timer expires on an address, SCTP should perform slow start by: ssthresh max(cwnd/2, 4*MTU) cwnd 1*MTU and ensure that no more than one SCTP packet will be in flight for that address until the endpoint receives acknowledgement for successful delivery of data to that address.大致意思如下在检测到丢包时更新 sstresh 和 cwnd 机制如下对原 ssthresh 减半但最大为 4 个 MTU 大小这个是致命的同时将 cwnd 更新为 ssthresh当 T3-rtx 重传定时器超时时对原 ssthresh 减半但最大为 4 个 MTU 大小但对 cwnd 更新为仅 1 个 MTU。通过上述两种机制可以看到在高丢包率的弱网环境中很容易进入到上述两种 case 中结合 flighting 的数据大小导致 sctp 协议可发送数据量奇小 cwnd 过小同时因为重传包的优先级高于新生成的数据包导致协议唯一的一个发送窗口一直在重传旧包新包很难获取发送机会这就导致了明显的队头阻塞现象。解决方案目标只是为了不使 CWnd 的大小降低的过快即在检测到丢包和 T3-rtx 超时时不要立即对 ssthresh 减半而是更加平滑的去降低并且提高最小值的上限通过这两种策略的优化可以保证 sctp 协议有很高的带宽抢占能力因为发送窗口越大带宽抢占能力就越高。清空队列通过上述策略优化发送窗口后可以大幅度提高 sctp 在弱网双向各30%丢包率下的带宽传输能力但是在更极端的网损40%丢包甚至更高场景下依然会出现队头阻塞现象发送端不再主动发送新插入的数据而是优先发送旧包未收到 Ack在实际应用场景中我们希望不论是否收到对端的确认都不应该阻塞新包的发送和旧包的清理以保证发送队列有一个快速的清理速度且保证所有的数据均有机会被快速的发送到网络中去。如果双方均为开源的实现我们可以随意修改 sctp可快速解决上述问题但是当一端为浏览器时我们只能考虑修改 Server 侧的协议实现以期可以间接的影响到对端浏览器让对端浏览器最为发送端时可以快速的清空发送队列避免队头阻塞答案就在 SACK 包中首先看下 SACK 包的协议定义https://datatracker.ietf.org/doc/html/rfc4960#section-3.3.43.3.4. Selective Acknowledgement (SACK) (3) This chunk is sent to the peer endpoint to acknowledge received DATA chunks and to inform the peer endpoint of gaps in the received subsequences of DATA chunks as represented by their TSNs. The SACK MUST contain the Cumulative TSN Ack, Advertised Receiver Window Credit (a_rwnd), Number of Gap Ack Blocks, and Number of Duplicate TSNs fields. By definition, the value of the Cumulative TSN Ack parameter is the last TSN received before a break in the sequence of received TSNs occurs; the next TSN value following this one has not yet been received at the endpoint sending the SACK. This parameter therefore acknowledges receipt of all TSNs less than or equal to its value. The handling of a_rwnd by the receiver of the SACK is discussed in detail in Section 6.2.1. The SACK also contains zero or more Gap Ack Blocks. Each Gap Ack Block acknowledges a subsequence of TSNs received following a break in the sequence of received TSNs. By definition, all TSNs acknowledged by Gap Ack Blocks are greater than the value of the Cumulative TSN Ack. 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 -------------------------------- | Type 3 |Chunk Flags | Chunk Length | -------------------------------- | Cumulative TSN Ack | -------------------------------- | Advertised Receiver Window Credit (a_rwnd) | -------------------------------- | Number of Gap Ack Blocks N | Number of Duplicate TSNs X | -------------------------------- | Gap Ack Block #1 Start | Gap Ack Block #1 End | -------------------------------- / / \ ... \ / / -------------------------------- | Gap Ack Block #N Start | Gap Ack Block #N End | -------------------------------- | Duplicate TSN 1 | -------------------------------- / / \ ... \ / / -------------------------------- | Duplicate TSN X | -------------------------------- Chunk Flags: 8 bits Set to all 0s on transmit and ignored on receipt. Cumulative TSN Ack: 32 bits (unsigned integer) This parameter contains the TSN of the last DATA chunk received in sequence before a gap. In the case where no DATA chunk has been received, this value is set to the peers Initial TSN minus one. Advertised Receiver Window Credit (a_rwnd): 32 bits (unsigned integer) This field indicates the updated receive buffer space in bytes of the sender of this SACK; see Section 6.2.1 for details. Number of Gap Ack Blocks: 16 bits (unsigned integer) Indicates the number of Gap Ack Blocks included in this SACK. Number of Duplicate TSNs: 16 bit This field contains the number of duplicate TSNs the endpoint has received. Each duplicate TSN is listed following the Gap Ack Block list. Gap Ack Blocks: These fields contain the Gap Ack Blocks. They are repeated for each Gap Ack Block up to the number of Gap Ack Blocks defined in the Number of Gap Ack Blocks field. All DATA chunks with TSNs greater than or equal to (Cumulative TSN Ack Gap Ack Block Start) and less than or equal to (Cumulative TSN Ack Gap Ack Block End) of each Gap Ack Block are assumed to have been received correctly. Gap Ack Block Start: 16 bits (unsigned integer) Indicates the Start offset TSN for this Gap Ack Block. To calculate the actual TSN number the Cumulative TSN Ack is added to this offset number. This calculated TSN identifies the first TSN in this Gap Ack Block that has been received. Gap Ack Block End: 16 bits (unsigned integer) Indicates the End offset TSN for this Gap Ack Block. To calculate the actual TSN number, the Cumulative TSN Ack is added to this offset number. This calculated TSN identifies the TSN of the last DATA chunk received in this Gap Ack Block.每一个 SACK 包中均包括一个字段Cumulative TSN该字段标识接收端已确认通知给 Application的最大包序号TSN通过此字段告诉发送端不要再发送小于此 TSN 的包并清空所有队列中小于等于此 TSN 的数据包其它的字段均不是最重要的可以自行决定是否调整。只有当发送端不断的接收到接收端发来的 SACK 包后通过其携带的强制前移的 “Cumulative TSN” 来清理本地的发送队列可以保证自己的发送队列一直处于一个较小的 Cache这样新插入的数据包便可以被快速的发送出去避免了因旧包未被 Ack 而导致的队头阻塞问题更加的贴近 UDP 的行为。SACK Chunk 源码首先整理下 sctp 协议内接收端组装sack 的数据结构 https://tools.ietf.org/html/rfc4960#section-3.3.4在 dcsctp 的代码中比较易懂定义如下class SackChunk : public Chunk, public TLVTraitSackChunkConfig { public: static constexpr int kType SackChunkConfig::kType; // 可以看出包序号使用的是 uint16_t只需两个字节 struct GapAckBlock { GapAckBlock(uint16_t start, uint16_t end) : start(start), end(end) {} uint16_t start; uint16_t end; bool operator(const GapAckBlock other) const { return start other.start end other.end; } }; SackChunk(TSN cumulative_tsn_ack, uint32_t a_rwnd, std::vectorGapAckBlock gap_ack_blocks, std::setTSN duplicate_tsns) : cumulative_tsn_ack_(cumulative_tsn_ack), a_rwnd_(a_rwnd), gap_ack_blocks_(std::move(gap_ack_blocks)), duplicate_tsns_(std::move(duplicate_tsns)) {} static absl::optionalSackChunk Parse(rtc::ArrayViewconst uint8_t data); void SerializeTo(std::vectoruint8_t out) const override; std::string ToString() const override; TSN cumulative_tsn_ack() const { return cumulative_tsn_ack_; } uint32_t a_rwnd() const { return a_rwnd_; } rtc::ArrayViewconst GapAckBlock gap_ack_blocks() const { return gap_ack_blocks_; } const std::setTSN duplicate_tsns() const { return duplicate_tsns_; } private: static constexpr size_t kGapAckBlockSize 4; static constexpr size_t kDupTsnBlockSize 4; const TSN cumulative_tsn_ack_; // 最大已确认包序号TSN 即为内部传输块的序号 const uint32_t a_rwnd_; // 接收窗口的大小 std::vectorGapAckBlock gap_ack_blocks_; // GAP 包序号范围一次聚合多个 std::setTSN duplicate_tsns_; // 收到的已确认的包序号 };这里可能有些疑问每次打包的 SACK 中其 gap_ack_blocks_ 和 duplicate_tsns_ 是否有最大个数/长度限制因为它们两个毕竟是要全部一个个的序列化到网络包中的答案是有的。两者 gap_ack_blocks_ 和 duplicate_tsns_ 单次限制上限为 20 个kMaxGapAckBlocksReported 和 kMazhimaxDuplicateTsnReported 均定义为 constexpr 值20声明在代码文件data_tracker.h 中。SACK 发包时机在 dcsctp 的实现中sack 的发送时机是动态的。在乜有数据包丢失时每秒钟发送一次当监测到丢包时针对每个数据包发送一次 sack当不直接发送 SACKS 时将使用 timer 控制 sack 的延迟发送比如 min(RTO/2200ms)。发送端接收到对端回应的 SACK 后判断如果其 cumulative tsn 比本地记录的最大的 last cumulative tsn 要大即没有回退则重启 T3_rtx_ 定时器。遗留问题RTT 计算有明显问题如下两种在 dcsctp 中看到 RTT 的计算是有漏洞的其在 sack 中没有 gap_ack_blocks 时通过 cumulative tsn 计算其 rtt存在两种风险:1、这个 sack 整体是有延迟的其计算 rtt 时是直接通过 sendts - current ts明显没有考虑 delay ack time2、其只有在没有 gap_ack_blocks 时即没有出现丢包时才统计其 RTT这样在丢包严重时可能会出现长时间无法更新 rtt或者在 rtt 和 loss 突然增大时出现长时间无法更新 rtt 的情况一直以旧的 rtt 为准。

相关新闻

革命性生成模型shortcut-models:告别迭代采样,单步生成高质量图像的终极指南

革命性生成模型shortcut-models:告别迭代采样,单步生成高质量图像的终极指南

革命性生成模型shortcut-models:告别迭代采样,单步生成高质量图像的终极指南 【免费下载链接】shortcut-models 项目地址: https://gitcode.com/gh_mirrors/sh/shortcut-models 在人工智能图像生成领域,速度与质量似乎总是难以兼得。…

2026/7/27 17:24:29阅读更多 →
先加密后签名还是先签名后加密?

先加密后签名还是先签名后加密?

先签名后加密还是先加密后签名呢? 先说结论,通常情况下应该先签名后加密。 签名算法计算出来的签名是为了验证消息的完整性,签名算法有比如HMAC-SHA256,加密算法则是为了保证消息的机密性,类似AES-GCM、AES-CBC&#…

2026/7/27 17:24:29阅读更多 →
从论文到代码:DCSCN-Super-Resolution关键实现细节解析

从论文到代码:DCSCN-Super-Resolution关键实现细节解析

从论文到代码:DCSCN-Super-Resolution关键实现细节解析 【免费下载链接】dcscn-super-resolution A tensorflow implementation of "Fast and Accurate Image Super Resolution by Deep CNN with Skip Connection and Network in Network", a deep learni…

2026/7/27 17:24:29阅读更多 →
如何高效使用手机号码定位查询工具:3分钟快速入门指南

如何高效使用手机号码定位查询工具:3分钟快速入门指南

如何高效使用手机号码定位查询工具:3分钟快速入门指南 【免费下载链接】location-to-phone-number This a project to search a location of a specified phone number, and locate the map to the phone number location. 项目地址: https://gitcode.com/gh_mirr…

2026/7/27 18:42:40阅读更多 →
PMP机构靠不靠谱?三查就知道—查PMI、查基金会、查有效期

PMP机构靠不靠谱?三查就知道—查PMI、查基金会、查有效期

你决定考PMP,打开浏览器搜索培训机构。满屏都是“PMI授权”“官方合作伙伴”“权威认证”——上百家机构,宣传语长得差不多,你根本分不清谁真谁假。 销售说得天花乱坠,承诺包过、保过、不过退费,你觉得反正都差不多&am…

2026/7/27 18:42:40阅读更多 →
LSPatch免Root框架深度解析:Android应用定制的完整技术方案

LSPatch免Root框架深度解析:Android应用定制的完整技术方案

LSPatch免Root框架深度解析:Android应用定制的完整技术方案 【免费下载链接】LSPatch LSPatch: A non-root Xposed framework extending from LSPosed 项目地址: https://gitcode.com/gh_mirrors/ls/LSPatch 在Android生态系统中,Root权限长期以来…

2026/7/27 18:42:40阅读更多 →
AI绘画提示词黑箱破解(工业级提示工程白皮书节选):基于2,143组AB测试数据,定位影响图像一致性最关键的6个词序变量

AI绘画提示词黑箱破解(工业级提示工程白皮书节选):基于2,143组AB测试数据,定位影响图像一致性最关键的6个词序变量

更多请点击: https://codechina.net 第一章:AI绘画提示词分享 AI绘画的核心驱动力之一是高质量的提示词(Prompt),它直接影响生成图像的构图、风格、细节与语义准确性。合理组织提示词结构,能显著提升模型对…

2026/7/27 18:42:40阅读更多 →
传统产品经理如何转型AI产品经理?5大关键顺序别颠倒!

传统产品经理如何转型AI产品经理?5大关键顺序别颠倒!

2026年,AI产品经理的岗位需求同比增长85%。越来越多的传统产品经理站在了职业的十字路口——向左是坚守熟悉的赛道,向右是拥抱AI的浪潮。 但很多人转型失败,不是因为不努力,而是因为顺序搞反了。 有人一上来就死磕机器学习算法&am…

2026/7/27 18:42:40阅读更多 →
BGE-M3联合嵌入在FastEmbed-rs中的应用: dense、sparse与ColBERT三合一

BGE-M3联合嵌入在FastEmbed-rs中的应用: dense、sparse与ColBERT三合一

BGE-M3联合嵌入在FastEmbed-rs中的应用: dense、sparse与ColBERT三合一 【免费下载链接】fastembed-rs Rust library for generating vector embeddings, reranking locally! 项目地址: https://gitcode.com/gh_mirrors/fa/fastembed-rs FastEmbed-rs是一个功…

2026/7/27 18:40:40阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/27 1:14:34阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/27 1:14:52阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/27 1:14:56阅读更多 →
SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

1. 项目概述:从寄存器手册到实战指南 如果你手头有一份类似德州仪器(TI)TMS320x240xA系列DSP的SPI模块技术手册,看着里面密密麻麻的寄存器位定义、时序图和公式,是不是感觉头大?这份资料虽然权威&#xff0…

2026/7/27 0:00:24阅读更多 →
【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/27 0:00:24阅读更多 →
2007-2023年各市区县生态文明建设示范区DID

2007-2023年各市区县生态文明建设示范区DID

数据简介 自改革开放以来,我国依赖高投入、高资源消耗和高污染等传统发展模式实现了经济短期内的快速增长, 然而这也导致了严重的生态环境危机。因此,国家有力于推动企业高质量经济发展,协同生态保护的方针,从而从201…

2026/7/27 0:00:24阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/27 16:57:54阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/26 19:05:21阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/26 19:05:21阅读更多 →