特征读写操作原语:读请求、写请求、写命令、通知、指示与确认

3.1 原语概述与分类

GATT 层定义了六种核心操作原语,用于客户端与服务器之间交换特征数据。根据数据传输方向与确认机制,这些原语可分为三大类:

  • 客户端发起的操作:读请求、写请求、写命令
  • 服务器主动推送:通知、指示
  • 链路层确认:写命令无确认,指示需显式确认
原语 方向 需要确认 最大数据长度 典型用途
读请求 (Read Request) Client → Server 是(读响应) ATT_MTU – 1 读取特征值
写请求 (Write Request) Client → Server 是(写响应) ATT_MTU – 3 可靠写入
写命令 (Write Command) Client → Server 否 ATT_MTU – 3 高速非可靠写入
通知 (Notification) Server → Client 否 ATT_MTU – 3 实时数据推送
指示 (Indication) Server → Client 是(确认) ATT_MTU – 3 重要事件确认

3.2 操作时序与数据流边界

每种原语的执行都受 ATT 层 MTU 限制。ATT_MTU 决定了单次操作可传输的最大有效载荷。常用默认 MTU 为 23 字节,扣除操作码和句柄后,特征值净荷上限见上表。实际部署中可通过 MTU 协商提升(如 512 字节)。

数据流边界规则:当特征值长度超过单次 ATT 操作净荷时,必须使用 长读取(Read Long)或 长写入(Prepare Write + Execute Write)复合流程。本课程后续章节会专项讲解。

实战提示:写命令与通知不具备链路层确认,上层应通过应用层 ACK 机制确保数据完整性;在丢包率高的 2.4GHz 环境下,优先使用写请求或指示。

3.3 协议栈 API 映射

以下以 Zephyr RTOS 的 BT GATT API 为例,展示各原语的函数调用:

// 读请求 – 客户端发起
int bt_gatt_read(struct bt_conn *conn, uint16_t handle,
                 uint16_t offset, struct bt_gatt_read_params *params);

// 写请求 – 可靠写,需等待响应回调
int bt_gatt_write(struct bt_conn *conn, uint16_t handle,
                  const void *data, uint16_t length,
                  bt_gatt_write_cb_t cb, void *user_data);

// 写命令 – 无确认,立即返回
int bt_gatt_write_without_response(struct bt_conn *conn,
                                   uint16_t handle,
                                   const void *data, uint16_t length,
                                   bool sign);

// 服务端推送通知
int bt_gatt_notify(struct bt_conn *conn,
                   const struct bt_gatt_attr *attr,
                   const void *data, uint16_t len);

// 服务端推送指示
int bt_gatt_indicate(struct bt_conn *conn,
                     const struct bt_gatt_attr *attr,
                     const void *data, uint16_t len);

3.4 实现流程与回调模型

  1. 客户端读流程:发送读请求 → 服务端返回 ATT Read Response → 触发客户端读回调。
  2. 客户端写请求流程:发送写请求 → 服务端处理并返回写响应 → 客户端写完成回调。
  3. 客户端写命令流程:发送写命令 → 服务端无响应 → 客户端立即继续下一条。
  4. 服务端通知流程:服务端调用 bt_gatt_notify → 链路层发送 ATT Handle Value Notification → 客户端通过订阅回调接收。
  5. 服务端指示流程:服务端调用 bt_gatt_indicate → 客户端收到后必须回复 ATT Handle Value Confirmation → 服务端确认回调被调用。

常见错误:

  • 混淆写命令与写请求:使用写命令时未做应用层确认导致数据丢失。
  • 指示未实现确认超时处理:Zephyr 默认超时 30 秒,若客户端未回复确认,服务端需重试或断开连接。
  • 单次特征值数据超过 ATT_MTU 净荷导致截断或协议错误。

3.5 调试与日志分析

使用 CONFIG_BT_DEBUG_LOG=y 开启协议栈日志,典型输出片段:

bt_gatt_write: handle 0x0012 len 4
bt_att_tx: opcode 0x52 (Write Request)
bt_att_rx: opcode 0x13 (Write Response)
bt_gatt_write_cb: err 0

通过抓取 HCI 日志可验证每个原语对应的 ATT PDU 字节流:

  • 写请求 ATT PDU:0x52 0x12 0x00 [data]
  • 写命令 ATT PDU:0x52 0x12 0x00 [data] (注意:写命令与写请求共用操作码 0x52,但命令端无响应)
  • 通知 ATT PDU:0x1B 0x12 0x00 [data]
  • 指示 ATT PDU:0x1D 0x12 0x00 [data]
  • 确认 ATT PDU:0x1E

3.6 性能与稳定性优化

优化维度 策略 影响
减少确认开销 高频数据使用通知而非指示 降低延迟,但可能丢包
MTU 协商 连接后将 ATT_MTU 提升至 512+ 减少长数据拆包次数
写命令批量发送 利用无确认特性合并多个特征写 提高吞吐,但无错误反馈
指示超时重试 设置合理超时(如 5 秒)并实现重发逻辑 提高重要事件送达可靠性

部署建议:在低功耗蓝牙产品中,建议将“写命令 + 应用层ACK”组合用于控制类特征(如按键状态),将“指示”用于告警类特征(如电池电量临界)。实际部署前必须经过信道干扰实测。

GATT 操作原语数据流 BLE Client BLE Server 读请求 读响应 写请求 写响应 写命令 无确认 通知 无确认 指示 确认 读/指示 写/通知 写命令 响应/确认 连接线