【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 @ 2024-01-23 12:13  壹点灵异  阅读(60)  评论(0编辑  收藏  举报