TLV通信协议之TLV封包的实现

  • TLV通信协议的简介

TLV,即Tag(Type)—Length—Value,是一种简单实用的数据传输方案。在TLV的定义中,可以知道它包括三个域,分别为:标签域(Tag),长度域(Length),内容域(Value)。这里的长度域的值实际上就是内容域的长度。

  • 只用TLV可能会出现问题

问题1:数据可能重合!如果你设置0x01为温度,那么后面如果还有个有个0x01可能是表示其他的数据的,而不是温度,这就会导致数据的重合。

解决方案:为了避免这个问题我们需要加一个报头,固定为0xFD,用来标志一个报文的开始。

问题2:数据可能会跳变出错!我们不能保证数据传输过程中数据不会发生跳变而导致接受端收到错误的信息,如:0x01表示温度,跳变为0x02就表示另外的东西了。

解决方案:我们需要在一个字节流末尾加一个CRC校验,传输前算一下字节流的大小,传输到另外一个端口后再算一下,对比前后两个CRC的值,如果相同,表示没有发生字节跳变,如果不同,那就舍弃!

加工后的TLV:

  • TLV封包的实现 

    1、头文件 

    #ifndef  _TLV_PACK_H_
    #define  _TLV_PACK_H_
    
    #include <stdint.h>
    #include <time.h>
    
    #define PACK_HEADER        0xFD 
    #define TLV_FIXED_SIZE     5
    #define TAG                0x01 
    #define TLV_BUFSIZE        256
    
    typedef struct tlv_buf_s 
    {
        char                   buf[TLV_BUFSIZE];
        int                    len;  /* data length */
        int                    size; /* buffer size */
    } tlv_buf_t;  
    int packtlv_time(char *buf, int size, struct tm *tm);
    
    int packtlv_msg(tlv_buf_t *tlv,struct tm *tm);
    
    void dump_buf(char *data, int len);
    
    #endif   /* ----- #ifndef _TLV_PACK_H_  ----- */
    
    

    2、源文件 

    /*********************************************************************************
     *      Copyright:  (C) 2020 shx
     *                  All rights reserved.
     *
     *       Filename:  tlv_pack.c
     *    Description:  This file 
     *                 
     *        Version:  1.0.0(04/20/2020)
     *         Author:  tianjincheng <473892093@qq.com>
     *      ChangeLog:  1, Release initial version on "04/20/2020 03:28:26 PM"
     *                 
     ********************************************************************************/
    #include <stdio.h>
    #include <string.h>
    #include "tlv_pack.h"
    #if 1
    int main(int argc, char *argv[])
    {
        tlv_buf_t tlv;
        time_t tmp;  
        struct tm *s_ptime;
        time(&tmp);  
        s_ptime = localtime(&tmp);
    
        packtlv_msg(&tlv, s_ptime); //将tlv的数据进行封包
        dump_buf(tlv.buf, tlv.len); //打印封包后的数据
    
        return 0;
    }
    
    #endif 
    int packtlv_time(char *buf, int size, struct tm *tm)
    {
        int     ofset = 0;   //记录buf的偏移量
        int     tlv_len = 0; //记录tlv的length 
        if (!buf|| size < TLV_FIXED_SIZE +6) //参数合法性检测
        {
            printf("error input argms\n");
            return -1;
        }
    
        buf[ofset] = PACK_HEADER;  //加入head
        ofset += 1; 
        buf[ofset] = TAG;          //加入tag
        ofset += 1;
        tlv_len = TLV_FIXED_SIZE +6;   //加入length
        buf[ofset] = tlv_len;
        ofset += 1;
        /*加入value */
        buf[ofset++] = tm->tm_year +1900; 
        buf[ofset++] = tm->tm_mon  + 1;
        buf[ofset++] = tm->tm_mday;
        buf[ofset++] = tm->tm_hour;
        buf[ofset++] = tm->tm_min;
        buf[ofset++] = tm->tm_sec;
    
        return ofset;
    
    }
    
    #if  1
    int packtlv_msg(tlv_buf_t *tlv,struct  tm *tm)
    {
        int               rv = 0;
        if( !tlv )
        {
            return -1;
        }
    
        memset(tlv->buf, 0, sizeof(tlv->buf));   /*  将buf置空 */
        tlv->size = sizeof(tlv->buf);            /*  设置buf的初始size*/
        tlv->len = 0;                            /*  设置buf的初始数据长度 */
    
        if( tm )
        {
            rv = packtlv_time(&tlv->buf[tlv->len], tlv->size, tm);
            if( rv > 0 )
            {
                tlv->len += rv;
                tlv->size -= rv;
            }
    
        }
        return 0;
    }
    
    void dump_buf(char *data, int len)
    {
        int  i = 0;
        for (i = 0; i< len; i++)
        {
            printf("0x%02x ", (unsigned char)data[i]);
        }
        puts(" ");
    }
    #endif 
    

     

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
TLV协议是一种常用的数据编码格式,它由Tag(标签)、Length(长度)和Value(值)三部分组成。在C语言中,可以使用结构体来实现TLV协议。 首先,定义一个TLV结构体,包含Tag、Length和Value三个成员: ```c typedef struct tlv { uint8_t tag; uint16_t length; uint8_t *value; } TLV; ``` 其中,Tag用一个字节表示,Length用两个字节表示,Value是一个指向字节数组的指针。 接下来,可以定义一些函数来进行TLV编码和解码: ```c // 编码一个TLV结构体 void encode_tlv(TLV *tlv, uint8_t *buf, int *len) { buf[0] = tlv->tag; buf[1] = (tlv->length >> 8) & 0xFF; buf[2] = tlv->length & 0xFF; memcpy(buf + 3, tlv->value, tlv->length); *len = 3 + tlv->length; } // 解码一个TLV结构体 void decode_tlv(TLV *tlv, uint8_t *buf, int len) { tlv->tag = buf[0]; tlv->length = (buf[1] << 8) | buf[2]; tlv->value = malloc(tlv->length); memcpy(tlv->value, buf + 3, tlv->length); } ``` 编码函数将一个TLV结构体编码成一个字节数组,解码函数将一个字节数组解码成一个TLV结构体,并将Value成员指向新分配的内存空间。 对于TLV序列,可以定义一个TLV链表结构体来存储多个TLV结构体: ```c typedef struct tlv_list { TLV *tlv; struct tlv_list *next; } TLV_LIST; ``` 其中,tlv指向一个TLV结构体,next指向下一个TLV链表结构体。 可以通过遍历TLV链表来实现多个TLV结构体的编码和解码。具体实现方法可以参考以下示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> typedef struct tlv { uint8_t tag; uint16_t length; uint8_t *value; } TLV; typedef struct tlv_list { TLV *tlv; struct tlv_list *next; } TLV_LIST; // 编码一个TLV结构体 void encode_tlv(TLV *tlv, uint8_t *buf, int *len) { buf[0] = tlv->tag; buf[1] = (tlv->length >> 8) & 0xFF; buf[2] = tlv->length & 0xFF; memcpy(buf + 3, tlv->value, tlv->length); *len = 3 + tlv->length; } // 解码一个TLV结构体 void decode_tlv(TLV *tlv, uint8_t *buf, int len) { tlv->tag = buf[0]; tlv->length = (buf[1] << 8) | buf[2]; tlv->value = malloc(tlv->length); memcpy(tlv->value, buf + 3, tlv->length); } // 添加一个TLV链表结构体 void add_tlv(TLV_LIST **list, TLV *tlv) { TLV_LIST *new_node = malloc(sizeof(TLV_LIST)); new_node->tlv = tlv; new_node->next = NULL; if (*list == NULL) { *list = new_node; } else { TLV_LIST *cur_node = *list; while (cur_node->next != NULL) { cur_node = cur_node->next; } cur_node->next = new_node; } } // 释放一个TLV结构体 void free_tlv(TLV *tlv) { free(tlv->value); free(tlv); } // 释放一个TLV链表结构体 void free_tlv_list(TLV_LIST *list) { while (list != NULL) { TLV_LIST *cur_node = list; list = list->next; free_tlv(cur_node->tlv); free(cur_node); } } int main() { // 创建一个TLV链表结构体,并添加两个TLV结构体 TLV_LIST *tlv_list = NULL; TLV *tlv1 = malloc(sizeof(TLV)); tlv1->tag = 0x01; tlv1->length = 3; tlv1->value = (uint8_t*)malloc(3); tlv1->value[0] = 0x01; tlv1->value[1] = 0x02; tlv1->value[2] = 0x03; add_tlv(&tlv_list, tlv1); TLV *tlv2 = malloc(sizeof(TLV)); tlv2->tag = 0x02; tlv2->length = 5; tlv2->value = (uint8_t*)malloc(5); tlv2->value[0] = 0x04; tlv2->value[1] = 0x05; tlv2->value[2] = 0x06; tlv2->value[3] = 0x07; tlv2->value[4] = 0x08; add_tlv(&tlv_list, tlv2); // 编码TLV链表 int tlv_list_len = 0; TLV_LIST *cur_node = tlv_list; while (cur_node != NULL) { tlv_list_len += cur_node->tlv->length + 3; cur_node = cur_node->next; } uint8_t *tlv_list_buf = malloc(tlv_list_len); int tlv_list_pos = 0; cur_node = tlv_list; while (cur_node != NULL) { encode_tlv(cur_node->tlv, tlv_list_buf + tlv_list_pos, &(cur_node->tlv->length)); tlv_list_pos += cur_node->tlv->length; cur_node = cur_node->next; } // 解码TLV链表 cur_node = NULL; int pos = 0; while (pos < tlv_list_len) { TLV *tlv = malloc(sizeof(TLV)); decode_tlv(tlv, tlv_list_buf + pos, tlv_list_len - pos); pos += tlv->length; add_tlv(&cur_node, tlv); } // 打印结果 cur_node = cur_node; while (cur_node != NULL) { printf("Tag: %02X\n", cur_node->tlv->tag); printf("Length: %d\n", cur_node->tlv->length); printf("Value: "); for (int i = 0; i < cur_node->tlv->length; i++) { printf("%02X ", cur_node->tlv->value[i]); } printf("\n"); cur_node = cur_node->next; } // 释放内存 free(tlv_list_buf); free_tlv_list(tlv_list); free_tlv_list(cur_node); return 0; } ``` 在这个示例中,首先创建一个TLV链表结构体,并分别添加两个TLV结构体。然后编码TLV链表成一个字节数组,并将其解码成另一个TLV链表结构体。最后打印结果并释放内存。 通过这个示例,可以看到使用C语言实现TLV协议是比较简单的。需要注意的是,由于TLV协议的长度是使用两个字节表示的,因此需要考虑其字节序。在本例中,假设使用的是大端字节序。在实际应用中,需要根据具体情况选择适当的字节序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XiaoCheng'Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值