GAP:决定设备的“身份”与“连接方式”

GAP层定义了一个BLE设备在射频层面的行为模式。最直接体现为四种角色:

  • 广播者(Broadcaster):只发送广播,不接受连接;
  • 观察者(Observer):只扫描广播,不发起连接;
  • 我外围设备(Peripheral):可以广播,作为从机接受连接;
  • 中心设备(Central):可以扫描,并作为主机发起一个或多个连接。

实际开发中,大多数产品会落在Peripheral(传感器节点、手环)或Central(手机、网关)这两个角色上。BoradCaster/Observer则常见于信标(Beacon)或纯单向数据采集场景。

GAP还决定了广播参数和连接参数。广播间隔影响被发现的速度和功耗;连接参数则直接决定了连接建立之后的通信节奏与功耗表现。连接参数中的三个核心项是:

  • 连接间隔(Connection Interval):两次连接事件之间的时间,间隔越短,响应越快,但双方射频唤醒越频繁,功耗越高;
  • 从机延迟(Slave Latency):允许从机跳过若干次连接事件而不响应,用于再无数据时进一步省电;
  • 监督超时(Supervision Timeout):超过这个时间没有成功通信就断开连接,通常建议设置为连接间隔的至少6倍以上,否则容易误判断链。

Peripheral可以在连接建立后向Central发起连接参数更新请求,但Central有权拒绝,因此,参数协商需要双方SDK都支持,并且应用层要做好请求被拒绝后维持旧参数的处理。


GATT/ATT:数据如何被组织和访问

这是BLE开发中接触最频繁的部分。你需要理解的是一个层次化的属性数据库模型。

最顶层是Profile,它对应一个完整的使用场景。Prfile又一个或多个Service组成;每个Service又包括若干Characteristic;每个characteristic包含一个值,以及可选描述符,用来描述值的格式或者配置访问方式。

从ATT的视角看,以上所有内容最终都存储为属性(Attribute)。每个属性由四要素构成:句柄(handle,唯一标识符)、类型(UUID)、值、权限。GATT在ATT之上赋予了这些属性以“服务”“特征”的语义结构。

开发中你需要记住的操作分类,对应GATT定义的11项特征,可以归为几组:

  • 发现类:发现所有的主服务、按UUID发现服务、发现特征、发现描述符;
  • 读类:读去特征值、读去描述符;
  • 写类:写入特征值(有回复/无回复)、写入描述符;
  • 通知类:Notify(服务器主动推送,客户端不确认)和Indicate(服务器推送,客户端需要确认)。

对于Peripherial开发者,你的主药工作是在本地构建GATT数据库(定义Service、Characteristic和权限),并在Central写入或订阅时做出响应。对于Central开发者,核心流程是发现服务特征,然后发起读写,或者订阅Notify/Indicate。


数据传输:MTU与分包是绕不开的现实约束

BLE的数据传输不是“发一段字节流”那么简单。ATT默认的MTU是23字节,扣除ATT操作码和句柄开销后,实际可用的有效载荷通常只有20字节左右。这意味着任何超出这个长度的应用数据,都需要在ATT/GATT层面进行分包与重组。

虽然MTU支持MTU交换,双方可以协商到更大的值(通常为247字节,实际有效载荷244字节),但你不能假设对端一定支持你期望的大小。开发中的稳健做法是:在连接建立之后先执行MTU交换,读取协商后的实际MTU,然后按照MTU-3(操作码+句柄开销)作为单词发送的有效载荷上限来组织数据。

如果使用Notify发送数据,应用层通常需要自己维护发送队列,应为底层发送是异步放入,连续快速写入可能耗尽协议栈缓冲区。对于需要传输较大文件或者数据流的场景,除了在GATT上做应用层分包,还可以考虑L2CAP面向连接信道(CoC).Coc绕过GATT的开销,提供基于credit的流控,适合大批量、连续的数据交换,但需要确认目标平台是否暴露了相应的API。


SM:配对、绑定与你实际需要配置的安全策略

配对和绑定对应用层数据收发是透明的——加不加安全机制,读写 GATT 特征的代码本身不变。但你需要决定安全等级以及是否存储长期密钥。

配对(Pairing) 的核心目的是生成用于加密链路的密钥。BLE 的配对通常分为三个阶段:配对特征交换(交换双方的 IO 能力和鉴权需求)、密钥生成(根据选择的方式生成短期密钥 STK 或长期密钥 LTK)、以及可选的密钥分发阶段。

绑定(Bonding) 则是在配对生成 LTK 之后,双方将 LTK 持久化存储(如写入 Flash)。下次重连时,可以直接用存储的 LTK 恢复加密链路,跳过完整的配对流程。只配对不绑定是可行的,但重连时需要重新走配对;实际产品中通常默认开启绑定。

开发中需要配置的关键项包括:IO 能力(设备是否支持显示、键盘输入,这决定了可用的配对方式)、MITM 保护是否开启(是否需要防中间人),以及配对模式(关闭配对 / 等待配对请求 / 允许配对)。一个常见的配置错误是:设备实际不具备键盘输入能力,却配置了需要输入 Passkey 的 IO 能力,导致配对流程无法正确完成。


L2CAP:开发者通常不直接操作,但需要知道它在哪里

L2CAP 在 Host 层底部承担多路复用和分割/重组的职责,把 ATT、SM 等上层协议的数据流通过不同的信道标识符复用到底层链路上。对大多数 GATT 开发者来说,不需要直接调用 L2CAP API。但当你遇到以下情况时,它就会浮出水面:

  • 你希望建立 GATT 之外的数据通道(L2CAP CoC),用于高吞吐或低开销的传输;
  • 你在调试工具中看到 L2CAP 层的分段与重组行为,需要理解 MTU 和底层数据长度之间的关系。

L2CAP 的 CoC 使用 credit 机制进行流控:接收方授予发送方一定数量的 credit,发送方每发一个包消耗一个 credit,从而避免接收端缓冲区被压垮。如果你的应用场景是持续的数据流(音频配置数据、固件升级块、日志回传),并且目标平台提供了 CoC API,它可以是一个比在 GATT Notify 上手动分包更干净的方案。


把以上内容串起来,一个 BLE 开发者在协议栈上的工作路径大致是:用 GAP 设定设备的可发现性与连接行为 → 用 GATT/ATT 定义数据模型和访问方式 → 在连接后处理 MTU 协商与数据分包 → 根据产品需求在 SM 层配置配对与绑定策略 → 在需要绕开 GATT 开销时评估 L2CAP CoC。Controller 层的细节由芯片厂商封装,你感知到的是连接参数的实际效果、射频吞吐能力和功耗表现,而不是直接操作链路层状态机。