Web Bluetooth 测 BLE 吞吐时会卡在默认 MTU
一次性电池供电的 BLE 监测设备只在同步数据时短暂连接手机。连接时间越短,蓝牙打开时间越短,平均功耗越低。因此在浏览器调试工具里做了 BLE 吞吐测试,分别测浏览器到 MCU 的上传速度,以及 MCU 通过 Notify 发给浏览器的下载速度。

最开始的结果很低:
上传速率:4096 B / 5350.5 ms = 765.5 B/s
下载速率:4096 B / 6998.7 ms = 585.3 B/s这个速度容易让人怀疑 MCU 忙、协议封包慢、串口日志太多,或者浏览器 JavaScript 处理不过来。后面的排查证明,真正踩到的是 Web Bluetooth 调试环境的边界:浏览器侧没有标准接口显式请求大 MTU,Windows 和 Chrome 没主动协商时,连接会停在默认 MTU 23。
现象是 MTU 一直只有 23
设备端打开 Notify 后读取到的 MTU 是 23。ATT Notify 的有效载荷需要扣掉 3 字节 ATT 头,因此每个 Notify 只能放 20 字节数据。
尝试在 MCU 侧主动发起 MTU Exchange,请求 247 字节,结果返回 0x02。在 WCH 的状态码里,0x02 表示 INVALIDPARAMETER。结合 WCH 库说明可以确认:GATT_ExchangeMTU() 是 GATT client 用来发起 MTU Exchange 的接口。当前设备是 peripheral/server,主动调用这条路不成立。
Web Bluetooth 也没有给网页暴露类似 Android requestMtu() 的接口。网页可以连接设备、读写特征、订阅 Notify,但不能直接设置 ATT MTU。浏览器是否请求大 MTU,取决于系统蓝牙栈和浏览器实现。这个项目在 Windows Chrome 下没有协商到大 MTU,所以设备侧只能按 20 字节分包。
应用任务影响很小
设备端同时运行 ADC 采样、心率计算、BLE 协议处理和串口日志。为了确认是否有 CPU 干扰,临时关闭心率计算任务,只保留 BLE 主循环。
关闭后速度只提升了约 100 B/s。这个结果说明心率计算对这次低速影响很小,也避免继续在算法任务和主循环调度上排查。
连接间隔决定 20B 小包的包率
MTU 无法放大后,剩下能调的主要变量是连接间隔。连接日志显示初始 connInterval 是 20。BLE 连接间隔单位是 1.25ms,因此实际间隔是 25ms。
下载 4096 字节需要 205 个 20 字节 Notify。实际耗时接近 7 秒,折算每秒约 29 个 Notify。这个包率符合 25ms 连接间隔下每次连接事件只发出少量包的表现。
后续把数据同步阶段的连接间隔请求改成 6,也就是 7.5ms,并在连接建立后尽早发起参数更新。再次测速后结果明显改善:
上传速率:4096 B / 810.0 ms = 5056.8 B/s
下载速率:4096 B / 1544.3 ms = 2652.3 B/s
这里没有解决 MTU,解决的是默认 MTU 下的小包发送频率。
下载已经接近当前理论上限
调参后的下载速度是 2652.3 B/s。这个数值已经接近当前条件下的理论上限。
当前 Web Bluetooth 调试环境里,MTU 仍是 23,Notify 有效载荷是 20 字节。连接间隔调到 6 后,每次连接事件间隔是 7.5ms。如果每个连接事件稳定发出一个 20 字节 Notify,理论吞吐大约是:
20 B / 0.0075 s = 2666.7 B/s实测 2652.3 B/s 和这个值非常接近。这个结果说明下载路径已经基本吃满了“默认 MTU + 7.5ms 连接间隔 + 每连接事件一包”的边界。
继续提升下载速度,需要改变底层条件:手机侧协商更大的 MTU,或者同一个连接事件里发出更多 Notify。继续只改应用层封包,收益会很有限。
这个坑的误导性
Web Bluetooth 调试 BLE 吞吐时,低速现象会把排查方向带偏:
- 看起来像浏览器 JavaScript 慢。
- 看起来像 MCU 心率算法抢 CPU。
- 看起来像 TinyFrame 或自定义协议开销太大。
- 看起来像 Notify 发送函数写得不够快。
实际证据集中在三个量上:
ATT_GetMTU()一直是 23。- MCU 作为 peripheral 不能主动完成 MTU Exchange。
- 连接间隔从 25ms 改到 7.5ms 后,下载速度接近 20B 小包理论上限。
因此,浏览器调试工具测出来的速度不能直接代表正式手机 App 的上限。它更适合验证协议、状态机和基础链路,不适合判断原生 App 能达到的最高吞吐。
仍然没有解决的遗憾
这次解决了默认 MTU 下的低包率,没有解决 Web Bluetooth 无法显式请求大 MTU的问题。
正式产品如果使用 Android 或 iOS 原生 App,应在手机侧主动请求更大的 MTU。大 MTU 能减少分包次数,降低协议开销和连接时长。浏览器调试工具做不到这一点,因此它需要按 20 字节包设计,并把测速结果理解为 Web Bluetooth 调试环境的结果。
产品实现上可以采用分阶段策略:
- 平时断开蓝牙或使用低功耗连接参数。
- 数据同步开始后请求短连接间隔。
- 浏览器调试阶段按 20 字节分包,确认状态机和数据可靠性。
- 正式 App 阶段请求大 MTU,再重新评估吞吐和功耗。
- 数据同步结束后恢复低功耗状态,或者直接断开并进入休眠。
结论
Web Bluetooth 测 BLE 吞吐时,浏览器侧不能显式请求大 MTU 是一个重要限制。Windows Chrome 没主动协商时,设备会停在 MTU 23,每个 Notify 只有 20 字节有效载荷。
在这个限制下,短连接间隔可以把 20 字节小包的发送频率拉起来。本次下载测速从约 0.6 KB/s 提升到 2.59 KB/s,并且已经接近当前 20 字节包和 7.5ms 连接间隔下的理论上限。
本文由 AI 辅助生成,可能存在错误或遗漏,请以实际资料和官方文档为准。