|
在嵌入式软件开发中经常看到有朋友自定义协议,主要还是资源受限,然后功能也相对比较专业,后续维护其实也简单很多,但到了项目的一定阶段或者规模又不得不考虑可扩展性、兼容性等等问题,那么协议上就感觉千奇百怪了,那么今天bug菌跟大家聊聊通信协议中的TLV格式,基本上自定义协议最终都会向该方式或者类似的方式去靠拢,所以一步到位多好~
1
TLV数据格式
嵌入式物联网中的TLV(Type-Length-Value)格式是一种高效、灵活的数据封装方式,广泛应用于资源受限的物联网设备通信中。
结构解析:Type(类型)标识数据的类型(如电压、温度、湿度等),通常用1-2字节表示。例如,0x01代表电压,0x02代表温度。类型基本上就决定了这个TLV数据单元的长度所占字节和Value的解析方式等。Length(长度)表示Value字段的字节数,可固定或变长编码。例如,1字节(0-255)或变长整数(节省空间)。Value(值)实际数据内容,长度由Length字段定义,如温度值3.11V,放大1000倍编码为整形两个字节0x0C 0x1C。介绍了TLV数据封装格式,那么下面再详细介绍下其三大特点:
2
类型自描述
每个TLV结构的第一部分为Type字段(通常为1-4字节),用于明确标识数据的语义和编码方式,前面在介绍该字段的时候有说明了一下。
但是该字段需要收发双方约定好,这样就诞生了类型映射表。
类型映射表:Type值通过预定义的协议规范或动态协商(如设备握手阶段)确定,接收方根据Type值选择对应的解析逻辑。 若Type值与实际数据格式不匹配(例如Type声明为整数但Value为字符串),接收方可直接报错。
这样的话就无需外部元数据,数据本身携带类型信息,解析器无需依赖额外的协议文档或配置文件,现在挺多高级一点的序列化工具都需要使用工具等,麻烦。
在兼容性方面,不同设备或协议版本可以通过扩展Type定义(如预留私有Type范围)实现兼容,旧设备可忽略未知Type。同样你进行协议升级的时候,,只需定义新Type值(如0x04表示PM2.5),旧设备可跳过未知字段,新设备解析新数据,当前前提是你需要定义较多的type字段。
3
动态变长
紧随Type后的Length字段长度并不是固定的,通常为1-4字节够了,它主要是用于声明Value部分的字节长度。
例如:
若Value是4字节整数,Length=0x04
若Value是可变长字符串"Hello",Length=0x05当然也可以更加灵活的编码,Length字段的字节数可根据协议设计动态调整。
短数据(≤255字节):Length用1字节表示;
长数据(如固件包):Length用4字节表示这样一方面能够节省避免固定长度字段的填充浪费,另一方面可以支持可变数据,以适应物联网场景中数据长度多变的需求(如传感器数据、配置参数、日志文本)。
不知道大家平时用过流式传输没,通过Length提前预知数据边界,无需等待完整数据包,做到接收方可边接收边解析数据。
4
高效二进制编码
TLV整体以二进制字节流传输,而非文本格式(如JSON、XML)。而且在协议约定中采用的是一种紧凑编码规则,比如:
整数使用最小字节数(如0x7F以内用1字节,超过则用2字节);
浮点数采用IEEE 754标准压缩;
枚举值直接用单字节表示等等,可以做到无需转换直接按字节偏移读取数据,在资源受限平台大家确实比较钟爱。按照TLV的数据封装自定义协议基本上能够满足大部分嵌入式应用场景了。
[img][/img]
[img][/img]
[img][/img] |
|