3. 协议栈架构:承载层、网络层、传输层、接入层、基础模型层、模型层

说实话,刚接触蓝牙Mesh协议栈的时候,我也有点懵。七层架构,名字还都挺像。但干过几个项目之后,你会发现这玩意儿设计得其实挺巧妙——每一层各司其职,把复杂的事情拆得清清楚楚。

今天我们就一层一层把它剥开。我会结合自己踩过的坑来讲,这样你理解起来会更实在。

一句话总结:蓝牙Mesh协议栈从下往上,依次解决“怎么发”、“发给谁”、“发的内容是什么”、“上层怎么用”这四个问题。每一层都只关心自己的事,互不干扰。

蓝牙Mesh协议栈架构 模型层(Model Layer) 定义设备行为:开关、调光、传感器状态等 基础模型层(Foundation Model Layer) 配置、管理、心跳等系统级模型 接入层(Access Layer) 应用数据格式定义、操作码封装 传输层(Transport Layer) 分包重组、可靠传输、分段确认 网络层(Network Layer) 中继、路由、消息认证、TTL控制 承载层(Bearer Layer) 物理传输:广播承载(PB-ADV)和 GATT 承载(PB-GATT) 应用层 ↑ 核心层 ↑ 网络层 承载层 💡 数据从上层往下走:模型层 → 基础模型层 → 接入层 → 传输层 → 网络层 → 承载层 接收方向相反:承载层 → 网络层 → 传输层 → 接入层 → 基础模型层 → 模型层

3.1 承载层(Bearer Layer)—— 消息的“运输车”

承载层是协议栈的最底层。说白了,它负责把数据从一台设备物理地传到另一台设备。蓝牙Mesh支持两种承载方式:PB-ADV 和 PB-GATT。

承载类型 传输方式 典型场景
PB-ADV(广播承载) 蓝牙广播包(Advertising Channel) Mesh节点间通信、配网
PB-GATT(GATT承载) 蓝牙连接(Proxy Protocol) 手机App通过代理节点接入Mesh

我记得第一次调试配网流程时,设备死活连不上。查了半天,发现是PB-ADV的广播间隔设得太短,导致丢包严重。后来把间隔调到规范推荐的20ms,问题就解决了。嗯,这种细节往往最坑人。

我的经验:PB-ADV用于Mesh节点之间的通信,效率高但受广播信道限制。PB-GATT用于非Mesh原生设备(比如手机)接入,通过代理节点转发。如果你的产品需要手机控制,PB-GATT是必经之路。

3.2 网络层(Network Layer)—— 消息的“交通指挥”

网络层是蓝牙Mesh的核心。它负责消息的中继、路由和认证。你想想看,一个Mesh网络里可能有几百个节点,消息怎么从A传到Z?全靠网络层。

网络层主要干这几件事:

  • 消息中继:节点收到消息后,根据TTL(生存时间)决定是否转发
  • 消息认证:每个网络层PDU都带有一个消息认证码(MIC),防止伪造
  • 地址解析:识别单播地址、组播地址、虚拟地址
  • 序列号管理:防止重放攻击

我曾经在一个项目中,网络里同时有50多个灯。结果发现有些灯收不到控制指令。排查下来,是TTL设得太小(默认是3),消息传不到远处的节点。把TTL调到7之后,全屋覆盖就没问题了。

注意:TTL不是越大越好。每经过一个中继节点,TTL减1。TTL太大,消息会在网络里“兜圈子”,浪费带宽。一般建议根据网络直径来设,家庭场景5-7就够了。

3.3 传输层(Transport Layer)—— 消息的“拆装工”

传输层负责把上层的大数据包拆成小段,或者把小段拼回大包。蓝牙Mesh的传输层分两种模式:

  • 未分段消息:一条消息能装下,直接发
  • 分段消息:一条消息太大,拆成多个Segment,接收方收齐后重组

分段消息有个关键机制叫分段确认(Segmented Acknowledgment)。发送方发完所有分段后,接收方回复一个确认包,告诉发送方哪些分段收到了、哪些丢了。丢了的会重传。

特性 未分段消息 分段消息
最大有效载荷 11字节(Access Payload) 最多可传384字节(32段×12字节)
可靠性 无确认 有确认,支持重传
适用场景 小数据、状态发布 大数据、固件升级

做OTA固件升级时,传输层就特别关键。我记得有一次升级一个灯,固件包有30KB,分了200多个Segment。结果网络稍微一拥堵,就有分段丢失,重传了好几次才成功。后来我优化了分段间隔和重传策略,升级成功率才提上来。

3.4 接入层(Access Layer)—— 消息的“翻译官”

接入层是应用数据和网络数据之间的桥梁。它定义了应用数据的格式,包括操作码(Opcode)和参数。

接入层的主要职责:

  • 解析操作码,确定这个消息是“开关”还是“调光”还是“读状态”
  • 封装应用数据,加上操作码和必要的参数
  • 校验消息是否合法

举个例子,一个开关命令在接入层的格式可能是:

Opcode: 0x8201 (Generic OnOff Set)
Parameters: 0x01 (开) / 0x00 (关)
TID: 0x12 (事务ID,防止重复执行)

接入层不关心消息怎么传、怎么路由,它只关心“这个操作码对应什么动作”。这种分层设计,让应用开发变得简单——你只需要关注业务逻辑,底层的事交给下层。

3.5 基础模型层(Foundation Model Layer)—— 网络的“管理员”

基础模型层是蓝牙Mesh预定义的一组系统级模型。它们负责网络的配置、管理和维护。说白了,没有这层,Mesh网络根本跑不起来。

主要的基础模型包括:

  • 配置模型(Configuration Model):配网、添加/删除密钥、设置发布/订阅地址
  • 健康模型(Health Model):节点状态监测、故障上报
  • 心跳模型(Heartbeat Model):节点间定期发送心跳,检测网络连通性

我遇到过一个问题:一个节点配网后,其他节点收不到它的消息。查了半天,发现是配置模型里的发布地址没设对。发布地址设成了单播地址,而不是组播地址。嗯,这种配置错误,在基础模型层就能发现。

避坑指南:基础模型层的配置一定要在配网阶段完成。我曾经为了省事,在运行时动态修改配置,结果导致消息风暴。后来老老实实按规范来,在配网阶段就把发布/订阅关系配好。

3.6 模型层(Model Layer)—— 应用的“业务逻辑”

模型层是协议栈的最顶层,也是开发者最常打交道的一层。它定义了设备的具体行为,比如灯的开关、调光、色温调节,传感器的温度上报,窗帘的开合等。

蓝牙Mesh规范定义了很多标准模型:

  • Generic OnOff Server/Client:开关控制
  • Light Lightness Server/Client:亮度调节
  • Sensor Server/Client:传感器数据
  • Time Server/Client:时间同步

模型之间通过状态(State)和消息(Message)交互。比如一个开关模型,它的状态是“开”或“关”,消息是“设置开”或“设置关”。

我在做智能灯项目时,用了Light Lightness Server模型。一开始以为只要实现亮度调节就行,后来发现还要处理状态绑定——比如亮度调到0时,灯应该自动关掉,而不是保持“开”状态但亮度为0。这些细节,模型层都定义得很清楚。

核心要点:模型层是面向业务的。你不需要关心消息怎么在网络里传,只需要实现模型定义的状态和消息处理逻辑。蓝牙Mesh的标准化模型,让不同厂商的设备可以互操作——只要都实现了同一个模型,就能互相理解。

3.7 各层之间的协作

说了这么多层,它们到底怎么配合?我给你画个数据流:

  1. 应用层(模型层)产生一个消息,比如“开灯”
  2. 接入层加上操作码,封装成Access PDU
  3. 传输层判断是否需要分段,如果需要就拆成多个Segment
  4. 网络层加上网络头(源地址、目的地址、TTL等),加密并计算MIC
  5. 承载层通过PB-ADV或PB-GATT把数据发出去

接收端反过来:承载层收到数据 → 网络层解密验证 → 传输层重组 → 接入层解析操作码 → 模型层执行动作。

每一层只处理自己该处理的事。这种分层设计的好处是:你改模型层的逻辑,不影响网络层;你优化网络层的路由策略,模型层完全无感。

我的建议:刚开始做蓝牙Mesh开发时,不要试图一次性理解所有层。先从模型层入手,写一个简单的开关模型跑通流程。然后慢慢往下挖,理解网络层的中继机制、传输层的分段确认。一层一层来,反而更快。