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

  • TLV通信协议的简介

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

TLV通信协议之TLV封包的实现_第1张图片

  • 只用TLV可能会出现问题

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

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

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

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

加工后的TLV:

TLV通信协议之TLV封包的实现_第2张图片

  • TLV封包的实现 

    1、头文件 

    #ifndef  _TLV_PACK_H_
    #define  _TLV_PACK_H_
    
    #include 
    #include 
    
    #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 <[email protected]>
     *      ChangeLog:  1, Release initial version on "04/20/2020 03:28:26 PM"
     *                 
     ********************************************************************************/
    #include 
    #include 
    #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 
    

     

 

你可能感兴趣的:(TLV)