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 交换的过程是这样的:

  1. 客户端(通常是手机)发起 MTU 请求,告诉服务器它支持的最大 MTU 值。
  2. 服务器回复 MTU 响应,告诉客户端它支持的最大 MTU 值。
  3. 双方取较小的那个值作为本次连接的 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 知识体系总览

下面这张图,我把本章的核心概念串起来了。你可以把它当作一个快速参考。

GATT 连接核心概念体系 GATT 层 ATT 层 L2CAP 层 链路层 (LL) 物理层 (PHY) 连接参数 连接间隔 / 从机延迟 监督超时 断连检测时间 事件长度 单次传输时间 MTU 交换 默认 23 字节 有效载荷 MTU - 3 字节 吞吐量计算 MTU × 频率 × 包数 自动重连的关键动作 1. 链路层重新建立连接 2. 重新进行 MTU 交换 3. 重新发现服务和特征,恢复 CCCD 配置

这张图把协议栈分层、连接参数、MTU 交换以及自动重连的关键动作都串在了一起。你可以看到,链路层是连接的基础,连接参数和 MTU 是性能的关键,而自动重连需要把这些全部重新走一遍。

2.6 本章小结

好,这一章的内容就这些。总结一下:

  • GATT 协议栈是分层的,自动重连主要涉及链路层和 GATT 层。
  • 连接参数中的监督超时直接影响断连检测的灵敏度,要合理设置。
  • MTU 交换必须在重连后重新做,否则默认 23 字节的 MTU 会严重影响传输效率。
  • 连接参数和 MTU 共同决定了实际吞吐量,设计时要综合考虑。