第2章 特征操作基础读/写/通知/指示:操作码、ATT PDU结构、MTU协商、流程时序

本章深入剖析GATT特征操作的最小执行单元——ATT协议栈。你将掌握四种核心操作的底层协议帧、MTU协商机制以及完整交互时序,为后续高层应用开发打下坚实的依赖边界控制基础。

本章学习目标
  • 准确辨认4类操作码(Read/Write/Notify/Indicate)的ATT PDU结构
  • 掌握MTU协商的客户端/服务端角色与报文交互流程
  • 能画出操作时序图并识别典型异常分支(超时、重传、流控)
  • 通过抓包验证MTU对通知/指示数据包长度的影响

2.1 ATT操作码与PDU结构

ATT(Attribute Protocol)定义在BLE 4.0+核心规范Vol.3 Part F。每个操作由客户端发起,服务端响应。操作码(Opcode)位于PDU首字节,决定了后续数据布局。

操作方向 操作码(Hex) ATT PDU结构 对应GATT操作
Client→Server 0x0A Opcode + Attribute Handle (2B) Read Request
Server→Client 0x0B Opcode + Value (可变长) Read Response
Client→Server 0x12 Opcode + Handle (2B) + Value (可变长) Write Request / Write Command
Server→Client 0x1B Opcode + Handle (2B) + Value (可变长) Notification / Indication
Server→Client 0x1D Opcode + Handle (2B) + Value (可变长) Indication(需要确认)

关键点:所有PDU的最大长度受当前ATT MTU约束,超出部分将被截断或分片(LL层处理)。

// ATT Read Request PDU 示例(十六进制)
0x0A  // Opcode
0x00 0x17  // Attribute Handle = 0x0017

// ATT Write Request PDU 示例
0x12  // Opcode
0x00 0x2A  // Handle = 0x002A
0x48 0x65 0x6C 0x6C 0x6F  // Value = "Hello"

// ATT Notification PDU 示例(Server主动推送)
0x1B  // Opcode
0x00 0x2A  // Handle = 0x002A
0x54 0x65 0x6D 0x70 0x3A 0x32 0x35 0x2E 0x33  // Value = "Temp:25.3"

2.2 MTU协商机制

MTU(Maximum Transmission Unit)决定ATT层可承载的最大有效载荷。默认值为23字节(3字节头 + 20字节数据)。通过MTU Exchange Request/Response可以提升至最大512字节(BLE 4.2+支持)。

协商流程如下:

  1. 客户端发送 MTU Exchange Request(Opcode 0x02),携带客户端支持的MTU值(2字节Little Endian)。
  2. 服务端回复 MTU Exchange Response(Opcode 0x03),携带服务端支持的MTU值。
  3. 双方取 min(客户端MTU, 服务端MTU) 作为后续连接的ATT MTU。
阶段 PDU示例(Hex) 说明
MTU Request(Client→Server) 02 F4 01 Opcode=0x02, Client MTU=0x01F4=500
MTU Response(Server→Client) 03 30 01 Opcode=0x03, Server MTU=0x0130=304
协商结果 min(500,304)=304 后续ATT有效载荷最大304字节
工程提示:MTU协商应在GATT Service Discovery之前完成。许多BLE协议栈(如ESP-IDF、Zephyr)默认在连接后立即自动发起协商。若应用需要大包传输(如OTA固件),请显式调用API提高MTU:
// Android (BluetoothGatt)
bluetoothGatt.requestMtu(512);

// iOS (CoreBluetooth)
peripheral.maximumWriteValueLength(for: .withoutResponse)
// 注意iOS不直接支持MTU协商,系统自动优化

// ESP-IDF
esp_ble_gattc_exchange_mtu(remote_bda, mtu_size);

2.3 四种操作的完整流程时序

以下SVG图展示一个典型GATT Read/Write/Notify/Indicate的交互时序,重点标注原子操作、确认与流控边界。

GATT特征操作时序图 Client Server MTU Exchange Request MTU Exchange Response MTU协商完成 (min C/S MTU) Read Request (0x0A) Read Response (0x0B) Write Request (0x12) Write Response (0x13) Notification (0x1B) Indication (0x1D) Handle Value Confirm (0x1E)
时序要点解析:
  • 读操作:请求→响应,响应必须包含完整的Value(允许空值)。
  • 写操作:Write Request需等待Write Response确认;Write Command(无响应)则直接丢弃,无反馈。
  • 通知(Notify):单向推送,Client无需确认。流量控制依靠LL层信用和ATT层MTU,无应用层确认。
  • 指示(Indicate):Server发送后,Client必须回复Handle Value Confirm(0x1E),否则Server不会发送下一条指示。这是关键流控边界。
  • 超时处理:ATT响应超时通常为30秒(可配置)。超时后Client应发起连接终止或重传。

2.4 常见错误与调试方法

错误现象 可能原因 调试手段
Read Response返回0长度 特征属性无可读权限,或服务端内部错误 检查CCC描述符配置;抓包确认Error PDU
Write Request无响应 特征权限为“Write Without Response” 用Write Command代替;查看栈日志
Notification/Indication未收到 CCC描述符未使能(未写入0x0001或0x0002) 使用BLE嗅探器检查CCC写操作
大包被截断 ATT MTU未协商或被限制为23 调用MTU Request;检查对端能力
Indication风暴导致App无响应 应用层未及时发送Confirm 在Confirm回调中尽快处理;检查线程阻塞
性能与稳定性优化:
  • MTU选择:并非越大越好。BLE 4.2 PHY层最多251字节有效数据,建议协商至247字节(头+数据匹配LL PDU)。过大的MTU会增加重传代价。
  • Notification流控:多数协议栈内部有发送队列(如Zephyr的BT_GATT_NOTIFY_MULTI),无需应用层逐包确认。但若通知频率超过20ms/包,可能触发LL层信令拥塞。
  • Indication并发限制:同一连接同一时刻只能有一个未确认的Indication。设计多特征推送时,若需要可靠性,考虑分时发送或使用多连接。
  • 写操作顺序:Write Command无顺序保证,Write Request保证顺序。若需要可靠顺序写入(如配置寄存器),必须使用Write Request + Response。

2.5 实战抓包示例(基于nRF Sniffer)

以下为一次MTU协商 + Read操作的真实PDU序列(Wireshark输出格式):

Frame 1: Advertising (同连接建立)
Frame 2: LL_CONNECTION_UPDATE_REQ (已过滤)
Frame 3: ATT MTU Exchange Request (0x02 0x00 0x01) — Client MTU = 256
Frame 4: ATT MTU Exchange Response (0x03 0x00 0x01) — Server MTU = 256
Frame 5: ATT Read By Group Type Request (Service Discovery)
...
Frame 12: ATT Read Request (0x0A 0x00 0x17)
Frame 13: ATT Read Response (0x0B 0x41 0x42 0x43) — Value = "ABC"
Frame 14: ATT Write Request (0x12 0x00 0x2A 0x44 0x45)
Frame 15: ATT Write Response (0x13) — ACK
Frame 16: ATT Handle Value Notification (0x1B 0x00 0x2A 0x31 0x32)
Frame 17: (无确认)
Frame 18: ATT Handle Value Indication (0x1D 0x00 0x2A 0x33 0x34)
Frame 19: ATT Handle Value Confirm (0x1E) — 由Client自动回复
调试命令示例(host controller interface):
# 使用hcitool查看连接MTU(Linux BlueZ)
btmon -w trace.log  # 实时捕获HCI日志
# 通过btgatt-cmd读取特征
bluetoothctl menu gatt
# 扫描后连接
# select-attribute /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/service000a/char000b
# read

2.6 本章知识结构一览

模块关键概念依赖边界
ATT PDUOpcode、Handle、Value、错误码MTU限制PDU长度
MTU协商Exchange Req/Resp、min策略必须在数据传输前完成
读操作Read Req/Resp、Read Long数据>MTU时需分块读取
写操作Write Req/Resp、Write Cmd、Prepare WriteWrite Cmd无流控,可能丢失
通知/指示Notif(0x1B)、Ind(0x1D)、Confirm(0x1E)Ind必须收到Confirm才发下一条