一、前言

本人做过多年嵌入式软件开发,使用过不少通信协议比如:modbus,mavlink,mqtt,capwap协议等,这些协议都有一些共同点,可以参考这些协议总结协议设计现在方法论。

  • 帧格式(3种字段)

3种必要字段:tlv,crc,设备id/地址等设备标识。

2种可选:flag能力集合协商,version版本协议兼容性。

  • 通信流程(7个阶段)

协议交互流程主要有7个过程:发现,握手,认证,数据通信,保活,加密,重传。

  • 设计点
  1. 使用tlv格式用于扩展,报文头部type字段报文类型,length表征报文长度,用于接收端分配buf。

  2. 链路带宽小的场景,协议层不做重传,由应用层做重传,若协议层做重传则会导致拥塞严重。

  3. 设备标识和路由:多级id列表用于接收端索引消息处理函数callback,比如:设备标识id,模块id,msg id。

  4. 报文完整性使用crc检验。

  5. 报文安全性:通常由认证和加密实现,嵌入式常用认证方式可以采用challenge机制。加密可以使用ssl协议,但是ssl需考虑证书过期的问题,可以选择定期交换密钥,以及AES加密CPU消耗比较高,需硬件支持。

  6. 协议兼容性:msg id要有前瞻性,使用2bye,65535个msg,方便后面扩展。定义version字段,实现前向兼容。

  7. 通信方式是:P2P还是P2MP,以及是否需要中间路由,设备角色定义等。

  8. publish/subscribe模型,还是选择cs模型。

完整协议设计考量见下文。

二、协议设计核心目标

  1. 可靠性:数据不丢、不错、不乱序(按需)

  2. 效率:头部开销小,传输效率高

  3. 安全性:防窃听、防篡改、防重放

  4. 可扩展:版本兼容、字段可扩、业务可增


三、协议流程交互(生命周期)

阶段关键设计点补充说明
1. 发现​广播/组播发现、被动监听、服务声明在局域网内用 UDP 广播,可包含协议版本、能力标识
2. 握手​协议版本协商、参数协商(MTU、心跳间隔、加密算法)可支持“版本降级”兼容,避免连接失败
3. 认证​Challenge-Response(如 HMAC-SHA256)、Token 机制、证书双向认证避免密码明文传输;可支持多级认证(设备级+用户级)
4. 数据通信​分片/重组、流控、QoS、确认机制区分命令型报文(需确认)和推送型报文(可丢失)
5. 保活​双向心跳、自动重连、连接健康度检测心跳可携带轻度状态信息(如CPU占用、信号强度)
6. 加密​链路加密(TLS/DTLS)或载荷加密(AES-GCM)资源受限设备可用 ChaCha20-Poly1305(比 AES 轻量)
7. 重传​选择性重传、超时与拥塞避免、去重机制带宽受限场景一般不使用协议层重传,使用应用层重传。

四、帧格式设计(通用头部建议)

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
┌───────────────────────────────────────────────────────────────┐
│  Magic(2B)  │Version│Flags │    Type/Message ID(2B)       │
├───────────────────────────────────────────────────────────────┤
│           Length(2B)         │         Sequence ID(2B)      │
├───────────────────────────────────────────────────────────────┤
│         Source ID(4B)        │       Destination ID(4B)     │
├───────────────────────────────────────────────────────────────┤
│                     Timestamp / Fragment                      │
├───────────────────────────────────────────────────────────────┤
│                       Payload(变长)                         │
├───────────────────────────────────────────────────────────────┤
│         CRC32 / Checksum(4B)        │
└───────────────────────────────────────────────────────────────┘

字段说明:

  • Magic:固定魔数,用于快速识别数据帧开始,也可用于字节对齐。

  • Version:4bit 主版本 + 4bit 次版本,主版本不兼容时需断开,次版本可向后兼容。

  • Flags:8bit 标志位,例如:

    ACK``FRAG``ENCRYPTED``COMPRESSED``REQUEST``RESPONSE``BROADCAST

  • Type/Message ID:消息类型编号,预留 0xFF00-0xFFFF 为厂商自定义。

  • Length:整个帧的长度(含头部)。

  • Sequence ID:用于请求-响应匹配,或报文去重。

  • Source/Destination ID:支持层级寻址,例如:[系统ID:设备ID:模块ID]。

  • Timestamp/Fragment:可用于分片偏移量,或毫秒级时间戳(用于延迟计算)。

  • CRC/Checksum:校验范围建议包含头部,防止头部篡改。

五、TLV 扩展设计

struct tlv {
    uint16_t tag;     // 高 2bit 表示类型(基本/扩展/厂商/保留)
    uint16_t length;  // 仅 value 长度
    uint8_t  value[];
};
  • Tag 设计:高 2bit 定义作用域,便于解析器跳过未知 TLV。

  • 嵌套 TLV:可用于复杂结构,但会增加解析复杂度。

六、QoS 分级设计

等级确认机制重传次数适用场景
QoS0无确认0传感器数据(允许丢包)
QoS1确认机制1-2控制命令、参数设置
QoS2双向握手3固件升级、关键配置
QoS3端到端应用层确认可配置跨网关重要数据

七、安全设计

  1. 密钥交换:
  • 首次连接可使用 Diffie-Hellman 交换临时密钥。

  • 长期密钥预置,定期更新(如每小时更换会话密钥)。

  1. 防重放:
  • 序列号 + 时间戳窗口验证。
  1. 设备身份:
  • 可使用设备唯一证书(如 ECC 证书),或芯片唯一 ID 派生密钥。

7.1 认证方式选择

嵌入式领域通常选择如下认证方式,主要通过两种方式认证:

1、验证数据:通过交互数据,验证比如SN码、ID、密码等正确性。

2、通过算法验证:比如哈希算法,challenge机制等都是通过算法校验。

常用的认证方式:

1、使用SN码、MAC等白名单方式,协议设计简单。

2、challenge挑战机制:服务器下发nonce,然后客户端使用哈希+nonce等以及本地的密码或者SN信息生成摘要数据发给服务器,由服务器使用相同方式校验结果。使用相同算法+密钥来认证。服务器和客户端都要配置密钥信息,算法是出厂预设。

3、PSK:预先共享密钥,服务器和客户端都配置相同密钥,预先共享给客户端,客户端配置密钥,常用于WIFI的认证方式。

4、报文级签名:MAVLINK的认证机制,使用固定的签名算法对报文生成摘要字段,只有通信双方知道密钥,才可以认证通过。

八、业务模型与路由

模型寻址方式适用场景
C/S 模型​目标设备 ID + 服务端口集中控制、数据采集
Pub/Sub​Topic 路由(可包含通配符)多对多消息分发、事件通知
P2P 直连​双方地址直接交换设备间直接通信,低延迟
网关路由​目标地址 = 网关ID + 设备ID跨网段、跨协议转发

建议:协议设计时可将寻址字段抽象为“目标地址列表”,支持多层路由。

九、其他重要考量点

1. 资源与性能平衡

  • 内存小的设备避免复杂重传逻辑,可交给上层。

  • 带宽小时启用头部压缩(如 Delta Encoding)。

  • CPU 弱时避免高强度加密,可硬件加速或降低加密频率。

2. 升级与兼容

  • 版本号明确,旧版本设备可安全降级通信。

  • 设计“能力协商”阶段,双方交换支持的功能列表。

  • 保留足够的 Message ID 和标志位供未来使用。

3. 错误处理

  • 定义标准错误码(设备忙、内存不足、参数无效等)。

  • 错误响应可携带错误详情 TLV。

4. 分片与重组

  • 若支持分片,需在头部设计分片标志、总分片数、当前分片索引。

  • 重组超时时间建议可配置。


九、建议设计流程

  1. 明确场景:确定设备能力、网络环境、业务模型。

  2. 定义消息:列出所有业务报文,归类为命令、数据、事件、响应。

  3. 设计帧结构:基于上述通用头部,按需删减字段。

  4. 画状态机:绘制协议各阶段的状态转换图,包括异常处理。

  5. 写文档:定义每个字段、每个消息的详细格式与语义。

  6. 实现样例:先实现 PC 端模拟器,再移植到嵌入式。

  7. 测试:重点测试网络异常(丢包、乱序、重复、延迟)下的行为。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐