2. 核心概念:GATT 协议栈回顾、连接参数与 MTU 交换
好,咱们正式开始第二讲。在做自动重连方案之前,有几个基础概念必须得先捋清楚。说白了,如果你不理解 GATT 协议栈的分层结构,不理解连接参数和 MTU 交换到底在干什么,那后面写重连逻辑的时候,很容易踩坑。
我个人习惯,每次带新人做 BLE 项目,第一件事就是让他们把协议栈的层次画出来。不是为了考试,而是为了定位问题。你想想看,当连接断了,你到底是哪一层出了问题?是物理层信号不好,还是链路层超时,还是 GATT 层没处理好?分不清的话,调试起来就像无头苍蝇。
2.1 GATT 协议栈分层回顾
BLE 协议栈从下往上,大致分这么几层:
- 物理层(PHY):负责 2.4GHz 频段的收发。现在主流是 1M PHY 和 2M PHY,还有长距离的 Coded PHY。
- 链路层(LL):负责连接建立、连接参数管理、重传、加密等。这是最核心的一层。
- L2CAP 层:负责数据的分包与重组,以及 MTU 的管理。
- ATT 层:属性协议,定义了客户端-服务器架构下的数据读写操作。
- GATT 层:基于 ATT 的上层框架,定义了服务、特征、描述符的组织方式。
嗯,这里要注意:我们平时说的「GATT 连接断开」,其实断的是链路层的连接。GATT 本身是无连接的,它只是基于 ATT 的通信框架。所以自动重连,本质上是在链路层重新建立连接,然后重新进行 GATT 层的服务发现和配置。
核心观点:自动重连 ≠ 自动恢复 GATT 会话。连接断了之后,所有 GATT 层的句柄、配置、CCCD 值都会丢失。重连后必须重新走一遍发现流程。
我记得有一次,一个同事在重连后直接往旧的句柄写数据,结果一直报错。他查了半天,最后发现是句柄变了。嗯,这个坑我后面还会细讲。
2.2 连接参数详解
连接参数是 BLE 连接中最容易被忽视,但又最关键的部分。它直接决定了功耗、延迟和吞吐量。
连接参数主要包括以下四个:
| 参数 | 含义 | 典型范围 | 影响 |
|---|---|---|---|
| 连接间隔(Connection Interval) | 两个连接事件之间的时间间隔 | 7.5ms ~ 4s(步进 1.25ms) | 间隔越小,延迟越低,功耗越高 |
| 从机延迟(Slave Latency) | 从机可以跳过多少个连接事件 | 0 ~ 499 | 延迟越大,从机越省电,但响应变慢 |
| 监督超时(Supervision Timeout) | 连接丢失的最大允许时间 | 100ms ~ 32s(步进 10ms) | 超时越短,断连检测越快,但容易误判 |
| 事件长度(Connection Event Length) | 每个连接事件中可用的传输时间 | 0 ~ 65535 μs | 影响单次传输的数据量 |
这里我要特别强调一下监督超时。我曾经在一个项目中,把监督超时设成了 5 秒,结果设备在信号不好的地方,连接断了要等 5 秒才能检测到,用户体验极差。后来我改成了 1 秒,配合适当的连接间隔,效果就好多了。
避坑指南:监督超时一定要大于连接间隔 × (1 + 从机延迟)。否则连接会频繁超时断开。公式:Supervision Timeout > Connection Interval × (1 + Slave Latency) × 2。这是蓝牙规范的要求。
2.3 MTU 交换
MTU(Maximum Transmission Unit)指的是 ATT 层一次能传输的最大数据包大小。默认的 MTU 是 23 字节,其中包含 3 字节的 ATT 头部,所以实际有效载荷只有 20 字节。
MTU 交换的过程是这样的:
- 客户端(通常是手机)发起 MTU 请求,告诉服务器它支持的最大 MTU 值。
- 服务器回复 MTU 响应,告诉客户端它支持的最大 MTU 值。
- 双方取较小的那个值作为本次连接的 MTU。
举个例子:手机支持 512 字节,设备支持 247 字节,那么最终 MTU 就是 247 字节。有效载荷就是 247 - 3 = 244 字节。
个人经验:我建议在连接建立后,第一时间做 MTU 交换。不要等到要发大包了才做。因为有些协议栈在 MTU 交换完成之前,会限制单次写入的数据量。如果你不主动请求,就一直用 23 字节的默认值,传输效率很低。
你想想看,如果你要传输一个 500 字节的固件升级包,用 20 字节的有效载荷要发 25 次;如果 MTU 提升到 244 字节,只需要发 3 次。这个差距是非常明显的。
2.4 连接参数与 MTU 的关系
连接参数和 MTU 不是孤立的,它们共同决定了实际的数据吞吐量。
理论吞吐量的计算公式大致是:
吞吐量 = (MTU - 3) × (1000 / 连接间隔) × (1 / 每个连接事件的包数)
举个例子:
- MTU = 247 字节
- 连接间隔 = 30ms
- 每个连接事件发 4 个包
- 理论吞吐量 ≈ 244 × (1000 / 30) × 4 ≈ 32,533 字节/秒 ≈ 31.7 KB/s
嗯,这只是理论值。实际还要考虑协议开销、重传、调度延迟等因素。但至少能给你一个参考。
关键点:在自动重连方案中,重连后必须重新进行 MTU 交换。因为 MTU 是连接级别的参数,连接断了就丢了。不要假设重连后 MTU 还是原来的值。
2.5 知识体系总览
下面这张图,我把本章的核心概念串起来了。你可以把它当作一个快速参考。
这张图把协议栈分层、连接参数、MTU 交换以及自动重连的关键动作都串在了一起。你可以看到,链路层是连接的基础,连接参数和 MTU 是性能的关键,而自动重连需要把这些全部重新走一遍。
2.6 本章小结
好,这一章的内容就这些。总结一下:
- GATT 协议栈是分层的,自动重连主要涉及链路层和 GATT 层。
- 连接参数中的监督超时直接影响断连检测的灵敏度,要合理设置。
- MTU 交换必须在重连后重新做,否则默认 23 字节的 MTU 会严重影响传输效率。
- 连接参数和 MTU 共同决定了实际吞吐量,设计时要综合考虑。