1. 项目概述
在低功耗蓝牙(BLE)技术体系中,属性协议(Attribute Protocol,简称ATT)扮演着至关重要的角色。作为GATT(通用属性规范)的基础协议,ATT定义了设备间交换属性数据的标准化操作方式。我曾在多个BLE项目中遇到过因ATT操作不当导致的通信问题,深刻理解掌握这些基础协议的重要性。
ATT协议的核心价值在于:
- 提供标准化的数据交互机制
- 支持多种可靠性和效率各异的操作类型
- 为上层服务发现和数据交换提供基础支撑
2. ATT操作分类与特性
2.1 操作类型对比分析
ATT协议定义了四种基本操作类型,每种类型在可靠性和响应机制上都有显著差异:
| 操作类型 | 可靠性 | 响应要求 | 典型应用场景 | 传输效率 |
|---|---|---|---|---|
| 请求/响应 | 高 | 必须响应 | 关键数据读写、服务发现 | 中等 |
| 命令(Command) | 低 | 无响应 | 批量数据写入、非关键操作 | 高 |
| 通知(Notification) | 低 | 无确认 | 传感器数据推送、状态更新 | 高 |
| 指示(Indication) | 高 | 需要确认 | 重要告警、安全相关通知 | 中等 |
实际开发中选择操作类型时,需要权衡可靠性和效率。例如在传输心率数据时,通常采用Notification以提高效率;而在传输安全认证信息时,则必须使用Indication确保可靠性。
2.2 操作码(Opcode)结构解析
所有ATT操作都通过操作码(Opcode)来标识其类型和方向:
code复制bit[7:6] - 操作类型:
00:命令(Command)
01:请求(Request)
10:响应(Response)
11:通知/指示(Notification/Indication)
bit[5:0] - 具体操作:
0x01:Exchange MTU请求
0x02:Find Information请求
...(其他操作码)
这种编码方式使得设备可以快速识别和处理不同类型的ATT报文。在实际调试中,通过分析Opcode可以快速定位通信问题。
3. 交换操作详解
3.1 MTU交换机制
MTU(Maximum Transmission Unit)交换是BLE连接建立后的第一个关键操作,直接影响后续通信效率。
3.1.1 交互流程
典型MTU交换包含以下步骤:
- 客户端发送Exchange MTU Request,携带其支持的MTU大小
- 服务端回复Exchange MTU Response,携带其支持的MTU大小
- 双方取较小值作为实际MTU
plaintext复制Client Server
| --- Exchange MTU Request ---> |
| |
| <-- Exchange MTU Response --- |
3.1.2 报文格式分析
Request报文:
code复制Offset | Field | Size | Value
-------+---------------+------+------------
0 | Opcode | 1 | 0x02 (Exchange MTU Request)
1 | Client Rx MTU | 2 | 客户端支持的MTU大小(如0x00A0表示160字节)
Response报文:
code复制Offset | Field | Size | Value
-------+---------------+------+------------
0 | Opcode | 1 | 0x03 (Exchange MTU Response)
1 | Server Rx MTU | 2 | 服务端支持的MTU大小
实际项目中,Android设备通常默认MTU为23字节,iOS为185字节。通过主动协商可以显著提升大数据量传输效率。
4. 发现操作深度解析
服务发现是BLE应用开发中最关键的环节之一,ATT提供了多种发现操作以适应不同场景。
4.1 Find Information Request
4.1.1 使用场景
用于发现指定句柄范围内的属性类型和句柄UUID对,特别适用于自定义服务发现。
典型应用:
- 发现设备支持的所有特性
- 枚举特定服务下的所有属性
4.1.2 报文格式
Request:
code复制0x04 (Opcode)
Start Handle (2字节)
End Handle (2字节)
Response格式有两种:
- 16位UUID格式(Format=0x01)
code复制0x05 (Opcode)
0x01 (Format)
List of:
Handle (2字节)
UUID (2字节)
- 128位UUID格式(Format=0x02)
code复制0x05 (Opcode)
0x02 (Format)
List of:
Handle (2字节)
UUID (16字节)
4.2 Read By Group Type Request
4.2.1 优化策略
这是发现主要服务(Primary Service)最高效的方式,相比Find Information可以减少30-50%的交互次数。
典型响应:
code复制0x11 (Opcode)
Attribute Data Length (1字节) // 每个属性数据的长度
List of:
Start Handle (2字节)
End Handle (2字节)
Value (变长,通常是服务UUID)
实际开发中,建议优先使用Read By Group Type来发现主服务,再结合其他操作发现服务详情。
5. 读取操作实现细节
5.1 Read Request基础操作
最基本的读取操作,适用于已知确切句柄的情况。
交互流程:
code复制Client Server
| --- Read Request (句柄) --> |
| |
| <-- Read Response (值) ---- |
错误处理:
- 如果句柄无效,返回Error Response
- 如果属性不可读,返回Error Response with 0x03(Write Not Permitted)
5.2 Read Blob Request分块读取
当属性值超过当前MTU大小时,需要使用分块读取机制。
典型场景:
- 读取长字符串描述符
- 获取大块配置数据
操作示例:
- 首次读取:Read Request获取前(MTU-1)字节
- 后续读取:Read Blob Request指定偏移量
- 重复直到获取完整数据
实际测试发现,分块读取时建议每次偏移量为(MTU-5)字节,以留出足够的协议开销空间。
6. 写入操作安全机制
6.1 Write Request可靠写入
最基本的写入操作,需要对方确认。
安全特性:
- 服务端必须显式响应
- 适合关键配置写入
- 保证数据完整性
6.2 Prepare/Execute Write事务机制
针对大数据写入的原子性操作,确保要么全部成功,要么全部失败。
典型流程:
- 客户端发送多个Prepare Write Request
- 服务端暂存数据并响应Prepare Write Response
- 客户端发送Execute Write Request提交或取消整个事务
- 服务端执行实际写入或丢弃数据
在固件升级(OTA)场景中,这种机制可以确保固件块的原子性写入,避免部分写入导致的设备变砖风险。
7. 通知与指示机制
7.1 Handle Value Notification
服务器主动推送数据的最高效方式,但不可靠。
配置步骤:
- 客户端写入CCC描述符(Client Characteristic Configuration)
- 服务端收到配置后开始发送Notification
- 客户端无需确认直接处理数据
7.2 Handle Value Indication
可靠的通知机制,需要客户端确认。
交互流程:
code复制Server Client
| --- Indication (数据) ----> |
| |
| <---- Confirmation -------- |
实际项目中,Indication的典型应用包括:
- 安全关键告警
- 需要确保送达的状态变更
- 需要客户端确认的配置更新
8. 错误处理与调试技巧
8.1 常见错误代码解析
| 错误代码 | 含义 | 典型原因 |
|---|---|---|
| 0x01 | 无效句柄 | 请求了不存在的属性 |
| 0x02 | 读取不被允许 | 属性不可读 |
| 0x03 | 写入不被允许 | 属性不可写 |
| 0x04 | 无效PDU | 报文格式错误 |
| 0x0A | 准备队列满 | Prepare Write请求过多 |
8.2 调试实战经验
-
MTU问题排查:
- 使用Wireshark捕获Exchange MTU交互
- 确认双方最终���用的MTU值
- 检查是否因MTU过小导致分片
-
服务发现失败处理:
- 确认起始/结束句柄范围正确
- 检查UUID是大端还是小端格式
- 验证服务是否确实存在于设备中
-
通知不工作排查:
- 确认CCC描述符已正确写入
- 检查服务端是否真的支持通知
- 验证属性权限是否配置正确
9. 典型连接流程优化
9.1 高效服务发现流程
优化后的服务发现流程可以显著提升连接速度:
- 交换MTU(可选)
- 使用Read By Group Type发现主服务
- 对每个服务:
- 使用Find Information发现特性
- 使用Read By Type发现描述符
- 配置需要的CCC描述符
9.2 数据交互最佳实践
- 对小数据使用Write Without Response提高效率
- 对关键数据使用Indication确保可靠性
- 对大块数据使用Prepare/Execute Write保证原子性
- 合理设置通知间隔,平衡功耗和实时性
在开发智能手环项目时,通过优化ATT操作流程,我们将服务发现时间从平均1200ms降低到400ms,显著提升了用户体验。关键优化点包括:
- 并行化服务发现请求
- 合理设置MTU大小
- 使用最高效的发现操作组合
