【TLV】一种TLV编码实现

项目地址:skullboyer/TLV (github.com)

介绍

TLV节点说明,tag字段高位表示有无嵌套

+-------------------------------------------------------------------------------------------+
| Single | Multi |
+-------------------------------------------------------------------------------------------+
| TLV | TL TLV TLV | TL TL TLV TLV |
|-----------------------------------------------|-------------------------------------------|
| 0xxx_xxxx | 1xxx_xxxx 0xxx_xxxx 0xxx_xxxx | 1xxx_xxxx 1xxx_xxxx 0xxx_xxxx 0xxx_xxxx |
+-------------------------------------------------------------------------------------------+

使用链表来管理tlv节点

=>create =>add =>add =>add
+-------------------+ +----------------+ +----------------+ +----------------+
| +-------------+ | | +----------+ | | +----------+ | | +----------+ |
| | head | | <--> | | list | | <--> | | list | | <--> | | list | |
| |-------------| | | | data | | | | data | | | | data | |
| | /\ | | | +----------+ | | +----------+ | | +----------+ |
| | tlv_group | | | /\ | | /\ | | /\ |
| +-------------+ | | tlv_group1 | | tlv_group2 | | tlv_groupx |
| /\ | +----------------+ +----------------+ +----------------+
| container |
+-------------------+

序列化,即二进制字节流

+-------------------------------------------------+
| TLVTLVTLVTLTLVTLVTLTLTLVTLVTLTLVTLVTLTLV |
+-------------------------------------------------+
| 1010101010000101111010010100111000100001'b |
+-------------------------------------------------+

快速开始

你可以使用本项目提供的脚本 do.sh 来快速的使用本项目

可以使用帮助命令方便查看 ./do.sh help

-*- help -*-
usage: ./do.sh [make] [exec] [mla] [clean] [help]
Example usage of the TLV mechanism
$ ./do.sh make
Check the TLV code for memory leaks
$ ./do.sh mla ON/OFF
$ ./do.sh make
Execute the program to view the results
$ ./do.sh exec (manual/smart)
Remove unnecessary code
$ ./do.sh clean

可以使用编译、执行命令来快速熟悉本项目的用法

$ ./do.sh make
$ ./do.sh exec manual/smart

可以使用MLA命令来检查本项目内存泄漏情况(详见:https://github.com/skullboyer/MLA)

$ ./do.sh mla ON/OFF
$ ./do.sh make
$ ./do.sh exec manual/smart

用法

在使用上分为手动与智能,区别在时间与空间的平衡,以及使用者的便利性,通过处理下述tlv节点来演示两种方式的使用规则

+-------------------------+
| TLV || TLV || TLV |
|-------------------------|
| TLV @ skull |
+-------------------------+
+-------------------------------------------------+
| TL | TLV || TLV |
|-------------------------------------------------|
| Half a loaf is better than no bread. 天 |
+-------------------------------------------------+
+------------------------------------------------------------ ----------+
| TL || TL | TLV | TLV || TL | TLV || TLV |
|-----------------------------------------------------------------------|
| All work and no play makes Jack a dull boy. 灵 |
+-----------------------------------------------------------------------+
+------------+
| TL | TLV |
|------------|
| 盖 |
+------------+

手动(执行顺序即为序列化结果序):

// test.c
int8_t tlv_producer_manual(uint8_t **data)
{
MAIN_ASSERT(*data == NULL);
tlv_container_t *container_root = tlv_container_create();
tlv_t *tlv = NULL;
// -*- single: TLV TLV TLV -*-
char *string = "TLV";
tlv_package(&tlv, tlv_tag_get_low(TEST_TAG01), strlen(string), string);
tlv_container_push(container_root, tlv);
tlv_destroy(&tlv);
string = "@";
tlv_package(&tlv, tlv_tag_get_low(TEST_TAG02), strlen(string), string);
tlv_container_push(container_root, tlv);
tlv_destroy(&tlv);
string = "skull";
tlv_package(&tlv, tlv_tag_get_low(TEST_TAG03), strlen(string), string);
tlv_container_push(container_root, tlv);
tlv_destroy(&tlv);
// -*- multi: TL TLV TLV -*-
tlv_container_t *container = tlv_container_create();
string = "Half a loaf is better than no bread.";
tlv_package(&tlv, tlv_tag_get_low(TEST_TAGa1), strlen(string), string);
tlv_container_push(container, tlv);
tlv_destroy(&tlv);
uint32_t value = 0xA9A4E5;
tlv_package(&tlv, tlv_tag_get_low(TEST_TAGa2), sizeof(value), &value);
tlv_container_push(container, tlv);
tlv_destroy(&tlv);
if (tlv_container_serialize(container) != 0) {
LOGD("tlv container serialize fail");
}
tlv_nested_package(&tlv, tlv_tag_get_high(TEST_TAGa0), container);
tlv_container_push(container_root, tlv);
tlv_destroy(&tlv);
tlv_container_destroy(&container);
// -*- multi: TL TL TLV TLV TL TLV -*-
container = tlv_container_create();
string = "All work and";
tlv_package(&tlv, tlv_tag_get_low(TEST_TAGca1), strlen(string), string);
tlv_container_push(container, tlv);
tlv_destroy(&tlv);
string = "no play";
tlv_package(&tlv, tlv_tag_get_low(TEST_TAGca2), strlen(string), string);
tlv_container_push(container, tlv);
tlv_destroy(&tlv);
tlv_container_t *container1 = tlv_container_create();
if (tlv_container_serialize(container) != 0) {
LOGD("tlv container serialize fail");
}
tlv_nested_package(&tlv, tlv_tag_get_high(TEST_TAGa0), container);
tlv_container_push(container1, tlv);
tlv_destroy(&tlv);
tlv_container_destroy(&container);
container = tlv_container_create();
string = "makes Jack a dull boy.";
tlv_package(&tlv, tlv_tag_get_low(TEST_TAGcb1), strlen(string), string);
tlv_container_push(container, tlv);
tlv_destroy(&tlv);
if (tlv_container_serialize(container) != 0) {
LOGD("tlv container serialize fail");
}
tlv_nested_package(&tlv, tlv_tag_get_high(TEST_TAGb0), container);
tlv_container_push(container1, tlv);
tlv_destroy(&tlv);
tlv_container_destroy(&container);
value = 0xB581E7;
tlv_package(&tlv, tlv_tag_get_low(TEST_TAGc1), sizeof(value), &value);
tlv_container_push(container1, tlv);
tlv_destroy(&tlv);
if (tlv_container_serialize(container1) != 0) {
LOGD("tlv container serialize fail");
}
tlv_nested_package(&tlv, tlv_tag_get_high(TEST_TAGc00), container1);
tlv_container_push(container_root, tlv);
tlv_destroy(&tlv);
tlv_container_destroy(&container1);
// -*- multi: TL TLV -*-
container = tlv_container_create();
value = 0x969BE7;
tlv_package(&tlv, tlv_tag_get_low(TEST_TAGd1), sizeof(value), &value);
tlv_container_push(container, tlv);
tlv_destroy(&tlv);
if (tlv_container_serialize(container) != 0) {
LOGD("tlv container serialize fail");
}
tlv_nested_package(&tlv, tlv_tag_get_high(TEST_TAGd0), container);
tlv_container_push(container_root, tlv);
tlv_destroy(&tlv);
tlv_container_destroy(&container);
// -*- serialize -*-
if (tlv_container_serialize(container_root) != 0) {
LOGD("tlv container_root serialize fail");
}

智能(序列化结果序取决于Tag定义,与执行顺序无关):

// test.c
int8_t tlv_producer_smart(uint8_t **data)
{
MAIN_ASSERT(*data == NULL);
tlv_container_t *container_root = NULL;
char *string = "TLV";
tlv_container_handle(&container_root, TEST_TAG01, strlen(string), string);
string = "@";
tlv_container_handle(&container_root, TEST_TAG02, strlen(string), string);
string = "skull";
tlv_container_handle(&container_root, TEST_TAG03, strlen(string), string);
string = "Half a loaf is better than no bread.";
tlv_container_handle(&container_root, TEST_TAGa1, strlen(string), string);
string = "All work and";
tlv_container_handle(&container_root, TEST_TAGca1, strlen(string), string);
string = "no play";
tlv_container_handle(&container_root, TEST_TAGca2, strlen(string), string);
uint32_t value = 0xA9A4E5;
tlv_container_handle(&container_root, TEST_TAGa2, sizeof(value), &value);
string = "makes Jack a dull boy.";
tlv_container_handle(&container_root, TEST_TAGcb1, strlen(string), string);
value = 0xB581E7;
tlv_container_handle(&container_root, TEST_TAGd1, sizeof(value), &value);
value = 0x969BE7;
tlv_container_handle(&container_root, TEST_TAGc1, sizeof(value), &value);
// -*- serialize -*-
if (tlv_container_serialize(container_root) != 0) {
LOGD("tlv container_root serialize fail");
}

设计

新增tlv节点在tlv-container中存在相同tag的处理逻辑

root root
.----------------------.--------. .-----------------------.--------.
| T1| T2| ... | Tn| Tm| | => | T1| T2| ... | Tn'| Tm| |
| L | L | ... | L | L |-> | | L | L | ... | L | L |-> |
| V | V | ... | V | V | | | V | V | ... | V | V | |
'----------------------'--------' '-----------------------'--------'
| ^
.---->-----------' `--. | remount
/ check \ pick off |
^ v |
.---. .---. .----.
| T | | Tn| | Tn'|
| L | | L | | L |
| V | | V | | V |
'---' '---' '----'
new | ^
.-' disassembly | assembly
v |
.--------.----. new .---. group .------------.----.
| T1| T2| ... | + | T | => | T1| T2| Tx| ... |
| L | L | ... | | L | | L | L | L | ... |
| V | V | ... | | V | | V | V | V | ... |
'--------'----' '---' '------------'----'

示例

示例test.c中演示了一种典型使用场景

+------------+ +-----------------------+ transfer +-------------------------+ +------------+
| TLV encode | ==> | data package and send | ===========> | data receive and verify | ==> | TLV decode |
+------------+ +-----------------------+ +-------------------------+ +------------+

共同进步

欢迎大家使用并issue反馈

posted @   壹点灵异  阅读(83)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
历史上的今天:
2019-01-23 【rt-thread】ENV构建STM32-BSP报错
点击右上角即可分享
微信分享提示