蓝牙低功耗(BLE)里"角色"特别容易把人搞晕:同样是"两端",有人叫 client/server,有人叫 central/peripheral,还有 broadcaster/observer。很多开发者下意识以为"主机就是 client、从机就是 server",结果调试时怎么都对不上。
核心原因:BLE 在不同协议层定义了完全不同的角色对,而且它们彼此独立。本文把这三对角色拆开讲清——它们分别在哪一层、管什么、能不能随便组合。
阅读前提:了解广播/连接基本流程即可。想深入看专栏里的《广播与扫描》《GATT 服务与特征值设计》。
| 角色对 | 所在层 | 解决的问题 | 是否建立连接 |
|---|---|---|---|
| Broadcaster / Observer | GAP(广播/扫描) | 单向广播、无需连接 | 否 |
| Central / Peripheral | GAP(连接) | 谁发起并维持连接 | 是 |
| GATT Server / Client | GATT(数据模型) | 谁拥有数据、谁来读写 | (建立在连接之上) |
一句话:广播层决定"能不能被看见",连接层决定"谁拉起链路",GATT 层决定"数据在谁手里、谁来取"。这三件事是正交的。
GAP(Generic Access Profile)在链路层之上定义设备"怎么被发现、怎么连起来"。它又分两种场景。
角色定义在 Host,动作发生在 Controller(重要澄清):这四个角色的名字和规则,全部由 GAP(Host 层) 规定;而它们对应的空中动作——发广播、扫广播、建连接——都交由 Controller 的链路层(Link Layer) 执行。链路层有五个状态(Standby / Advertising / Scanning / Initiating / Connection),GAP 的四种角色,本质就是把这些 LL 状态按"可连接与否"组合出来:Broadcaster = LL 的 Advertising(不可连接)、Observer = LL 的 Scanning、Peripheral = LL 的 Advertising(可连接)+ Slave、Central = LL 的 Initiating + Master。
所以不要按 controller / host 去切分 Broadcaster/Observer 与 Central/Peripheral:前者是 LL 的 Advertising/Scanning 状态(不连),后者是 LL 的 Initiating + Connection 状态(连),二者都是"GAP 管定义、LL 管执行"。两对角色的区别只在连不连,不在属于哪一层。
ADV_NONCONN_IND。LE Set Scan Enable 的扫描者角色。这对角色用于"单向信息发布":商场信标给手机推位置、温度传感器周期广播读数给网关。两端永不断连,省电到极致。
ADV_IND / ADV_DIRECT_IND),等待被连。连接后成为链路的 Slave(从)。心率带、智能锁、BLE 传感器通常扮演这个角色。CONNECT_IND 把链路拉起来,连接后是链路的 Master(主)。手机、网关、主机通常扮演这个角色。注意:Central/Peripheral 只在"连接建立 + 连接期间"有意义。连接一旦断开,角色随之消失。一个 Central 可以同时连多个 Peripheral(比如手机连手环+耳机+体重秤),而 Peripheral 通常只连一个 Central(虽规范允许多主,工程上少见)。
旧文档常把 Central/Peripheral 叫 Master/Slave,新版规范统一用 Central/Peripheral,建议丢掉主从这套说法。
连接建好之后,数据怎么组织、谁读写,由 GATT(Generic Attribute Profile)定义。这里是另一对角色:
关键点:GATT 的 Server/Client 跟"谁发起连接" 完全无关。Server 只是"数据在谁那里",Client 只是"谁来取数据"。
这是全文重点。请记住:
GAP 角色(Central/Peripheral)≠ GATT 角色(Client/Server)。
它们可以自由组合。常见四种搭配:
| 设备 | GAP 角色 | GATT 角色 | 例子 |
|---|---|---|---|
| 手机 App | Central | Client | 连手环读心率 |
| 心率带 | Peripheral | Server | 暴露心率特征 |
| 手机(同时) | Central | Server | 手机也把自己的时间/设备信息服务暴露给手环 |
| 网关 Hub | Central | Client + Server | 连多个传感器取数,同时把汇总数据对外暴露 |
最反直觉的例子:手机和手表配对时,手机通常是 Central + GATT Client(去读手表的 HR);但手表要同步手机的时间,得反过来读手机的 GATT Server——此时手机在同一连接里又成了 GATT Server。所以"谁是 Server"是按 GATT 事务方向定的,不是按设备定的。
另一个例子:有些 Peripheral 同时是 GATT Client。比如一个 BLE 键盘(Peripheral,被手机连),它想获取手机上的时间服务来校时,就会作为 GATT Client 去读手机的 GATT Server。外围设备照样能当 client。
新手还常把这几件事混为一谈,这里划清界限:
Discover All Primary Services 等过程,把对端属性表读出来。这跟 Observer 扫广播是两码事,一个在空中(链路层),一个在连接里(GATT 层)。所以你问题里的 "discover / observer" 其实分属两层:Observer 管"空中发现设备",discover(GATT discovery)管"连上后发现服务"。别因为都带"发现"就当成一回事。
ADV_EXT_IND / AUX_ADV_IND 的 AdvMode 字段决定可连接/可扫描/不可连接,从而区分 Broadcaster vs Peripheral、Observer vs Central 的"能不能连"。LE Create Connection,扩展广播对应 LE Extended Create Connection);Peripheral 在收到连接请求后完成连接。GATT Server 在应用层注册服务表;GATT Client 调用 discovery / read / write API。AUX_SCAN_REQ)可能回扫描响应,但绝不接受连接,别去 CONNECT 它。CONNECT_IND(定 Central/Peripheral),再看 ATT 层谁发 Read(定 Client/Server),两层分开看。BLE 的"角色"有三套、分三层:链路层广播用 Broadcaster/Observer(不连接)、连接用 Central/Peripheral(谁拉链路)、GATT 用 Server/Client(数据在谁手里);其中只有后两者常被混淆,但记住"建链的人不一定是拿数据的人"——GAP 角色和 GATT 角色正交,可以任意组合。下次有人拍胸脯说"从机就是 server",你就知道该纠正了。