【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
反馈
再牛逼的梦想也架不住傻逼似的坚持
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
2019-01-23 【rt-thread】ENV构建STM32-BSP报错