3. 协议栈架构总览:六层职责与数据流

蓝牙Mesh协议栈,说白了就是一套分层的通信规则。每一层各司其职,又互相配合。我刚开始接触Mesh时,总觉得层数太多记不住。后来在项目里调过几次bug,才真正理解——分层不是给你添乱的,是帮你定位问题的。

这一章,我们从上到下捋一遍。从最靠近应用的Profile Layer,一路到底层的Bearer Layer。每层干什么、数据怎么流、调试时该盯哪里,我都会结合自己的踩坑经验来讲。

核心观点:蓝牙Mesh协议栈共6层。数据从应用发出,逐层封装,最后通过射频发出。接收端反向解封装。每一层都有固定的PDU格式和职责边界。

3.1 整体架构图

先看一张总图。我习惯把协议栈想象成一根水管——数据从一头进去,经过几个阀门,从另一头出来。每个阀门就是一层。

蓝牙Mesh协议栈六层架构与数据流 蓝牙Mesh协议栈六层架构与数据流 发送端 Profile Layer 模型/状态/消息 Access Layer 应用密钥/访问控制 Upper Transport 分片/重组/加密 Lower Transport 段确认/重传 Network Layer 网络密钥/中继/路由 Bearer Layer PDU收发/广播 接收端 Profile Layer 模型/状态/消息 Access Layer 应用密钥/访问控制 Upper Transport 分片/重组/加密 Lower Transport 段确认/重传 Network Layer 网络密钥/中继/路由 Bearer Layer PDU收发/广播 发送端:逐层封装 → 接收端:逐层解封装 每层只处理本层头部,不越界操作

这张图我建议你保存下来。调试时遇到问题,先定位是哪一层出的错,再去看具体细节。我自己就是这么干的。

3.2 Profile Layer(模型层)

这是最靠近应用的一层。说白了,它定义了一个设备"能干什么"。比如一个灯,它有Generic OnOff Server模型,能响应开关命令。一个开关,它有Generic OnOff Client模型,能发送开关命令。

Profile Layer的核心职责:

  • 定义模型(Model)及其行为
  • 管理状态(State)和状态绑定
  • 处理应用层消息的语义

我的经验:调试时如果发现设备行为不对,先检查模型ID是否匹配。我曾经花了两天查一个灯死活不亮的问题,最后发现是Client和Server的模型ID对不上。嗯,这种低级错误最容易让人抓狂。

3.3 Access Layer(访问层)

Access Layer是Profile Layer和Transport Layer之间的桥梁。它负责两件事:应用密钥加密和访问控制。

你想想看,一个开关发了一条"开灯"命令,这条命令必须用应用密钥加密。只有拥有相同应用密钥的设备才能解密。这就是Access Layer干的活。

Access Layer的关键操作:

  • 接收来自Profile Layer的消息
  • 使用应用密钥(AppKey)加密消息
  • 添加Access头部(操作码、参数等)
  • 将加密后的PDU传递给Upper Transport Layer
字段 长度 说明
Opcode 1-3字节 操作码,标识消息类型
Parameters 可变 消息参数,如开关状态值
TransMIC 4字节 传输层消息完整性校验

注意:Access Layer只使用应用密钥加密。网络密钥(NetKey)是Network Layer的事。这两把钥匙千万别搞混。我在项目中见过有人把NetKey当AppKey用,结果全网设备都收不到消息。

3.4 Upper Transport Layer(上层传输层)

这一层负责分片与重组。蓝牙Mesh的底层PDU有长度限制(通常15字节左右)。如果应用层消息太长,Upper Transport Layer会把它切成多个片段。

举个例子。你要发送一条配置消息,长度30字节。Upper Transport Layer会把它切成2个片段,每个片段加上序列号。接收端收到后,按序列号重组。

Upper Transport Layer的职责:

  • 应用数据的分片(Segmentation)
  • 接收端重组(Reassembly)
  • 传输层加密(Transport Encryption)
  • 生成传输层消息完整性校验(TransMIC)

避坑指南:我曾经遇到一个场景——设备频繁掉线,抓包发现Upper Transport Layer的分片总是丢包。后来发现是底层射频干扰导致片段丢失,而Upper Transport Layer没有重传机制。解决方案是降低分片数量,或者改用更短的命令。

3.5 Lower Transport Layer(下层传输层)

Lower Transport Layer是Upper Transport Layer的"快递员"。它负责把分片后的数据段(Segment)可靠地送到对端。

这一层引入了段确认(Segment Acknowledgment)和重传(Retransmission)机制。发送端发出一个段后,会等待接收端的ACK。如果超时没收到,就重传。

Lower Transport Layer的核心机制:

  • 段编号(SeqAuth)管理
  • ACK超时与重传
  • 块确认(Block ACK)——一次确认多个段
  • 取消未确认的段(Cancel)

你想想看,如果Upper Transport Layer切了10个段,Lower Transport Layer会逐个发送并等待确认。接收端收到后,回复一个Block ACK,告诉发送端"我收到了第1、2、4段,第3段丢了,重发一下"。这种机制在Mesh网络中非常实用,因为无线环境本身就不稳定。

3.6 Network Layer(网络层)

Network Layer是协议栈的"交通警察"。它负责消息的中继(Relay)、路由(Routing)和网络密钥加密。

一个Mesh网络里,消息可能经过多个节点才能到达目的地。Network Layer决定了消息该往哪走。它使用TTL(生存时间)字段控制跳数,防止消息在网络里无限循环。

Network Layer的PDU格式:

字段 长度 说明
IVI 1位 IV索引的最低有效位
NID 7位 网络标识符,用于识别NetKey
CTL 1位 控制消息标志
TTL 7位 生存时间,每跳减1
SEQ 24位 序列号,防重放攻击
SRC 16位 源地址
DST 16位 目的地址
TransportPDU 可变 上层传输层PDU
NetMIC 8字节 网络层消息完整性校验

我的调试技巧:抓包时先看Network Layer的TTL字段。如果TTL为0,说明消息已经到最大跳数了。如果TTL很大但消息还是没到目的地,那问题可能出在中继节点上——它可能没有启用中继功能。

3.7 Bearer Layer(承载层)

这是最底层,直接和硬件打交道。Bearer Layer负责把Network PDU通过射频发出去,或者从射频收进来。

蓝牙Mesh定义了两种Bearer:

  • Advertising Bearer(广播承载):使用BLE广播信道发送。这是Mesh网络的主要承载方式。
  • GATT Bearer(GATT承载):通过BLE连接发送。主要用于配网场景,或者手机App与Mesh设备通信。

Bearer Layer的职责:

  • 将Network PDU封装成BLE广播包或GATT数据包
  • 管理广播间隔和信道选择
  • 处理物理层的收发中断

注意:Advertising Bearer有广播间隔限制。蓝牙Mesh规范建议广播间隔20ms到10.24s之间。间隔太短会占用过多信道,太长会导致延迟过高。我一般建议在100ms到500ms之间调整,具体看你的应用场景。

3.8 数据流全景

现在我们把六层串起来,看一条消息从发送到接收的完整路径。

发送端数据流:

  1. 应用层调用模型接口,发送"开灯"命令
  2. Profile Layer将命令封装成Access消息
  3. Access Layer用AppKey加密,添加操作码
  4. Upper Transport Layer检查长度,如果需要则分片
  5. Lower Transport Layer发送每个段,等待ACK
  6. Network Layer添加网络头部,用NetKey加密
  7. Bearer Layer通过射频广播出去

接收端数据流(反向):

  1. Bearer Layer收到射频数据,提取Network PDU
  2. Network Layer解密,验证NetMIC,检查TTL
  3. Lower Transport Layer检查段序号,回复ACK
  4. Upper Transport Layer重组分片,验证TransMIC
  5. Access Layer用AppKey解密,验证访问权限
  6. Profile Layer解析操作码,调用对应模型处理

一句话总结:发送端逐层加头加密,接收端逐层去头解密。每一层只关心自己的头部,不越界操作。这就是分层设计的美妙之处——出了问题,你只需要查那一层。

3.9 调试时的分层思维

最后分享一个我自己的调试框架。遇到Mesh通信问题时,我会按层排查:

现象 可能出问题的层 排查手段
设备收不到任何消息 Bearer Layer / Network Layer 检查射频是否正常、NetKey是否匹配
能收到消息但内容乱码 Access Layer / Upper Transport 检查AppKey、分片序号是否一致
消息能收到但设备不响应 Profile Layer 检查模型ID、状态绑定是否正确
消息延迟高 Lower Transport / Bearer 检查广播间隔、重传次数

嗯,这套方法帮我省了不少时间。你调试时也可以试试——先定位层,再定位具体问题。别一上来就翻代码,那样容易迷失方向。