TLV协议的装包与解包(C语言)

文章目录

  • 1.TLV简介
  • 2.TLV的封包
  • 3.TLV的解包

1.TLV简介

TLV :即Tag(Type)-Length-Value,它包含三个域,第一个Tag为要封装的数据的类型域,第二个Length为封装的总的数据长度,第三个Value为要装入数据的值。其实就是一个简单的自定义通信协议,将要传送的数据进行编码组织将其发送出去的过程。
TLV协议的装包与解包(C语言)_第1张图片
这是基本的tlv报文格式,在实际应用中我们可能会碰见在传输过程中数据发生跳变,这时候我们需要在一个字节流末尾加一个CRC校验,传输前算一下字节流的大小,传输到另外一个端口后再算一下,对比前后两个CRC的值,如果相同,表示没有发生字节跳变,反之,则舍弃。
加工后tlv报文:
TLV协议的装包与解包(C语言)_第2张图片
PACK_HEADE是自己定义的(0xFD),大小通常为一个字节;Tag也是自己定义,通常为一个字节;Length的大小要看你的数据所占用的字节大小,它的大小为包头大小+Tag大小+Length大小+校验和大小+数据字节大小,自身一般占用一个字节;crc校验和一般占两个字节。发送过程中如果不加头,发送的数据0x05 0x02 0x3c,在接收端就会以Tag(Type)-Length-Value顺序进行解析,正常情况下可以获取到正确的值,但是当发生数据跳变或者混入其他数据时,接收端按照之前的顺序解析就会出错,当我们加上头的时候,接收端解析的时候会先找到包头,然后按顺序解析,但是这样还是有出错的可那,但是加上crc校验和之后,crc根据接收到的数据计算出一个校验和,用来和装包装进去的校验和进行比较,如果相同说明这一帧数据正确,接收端才会开始解析数据,如果不正确就不解析。

2.TLV的封包

下面是我对获取到的温度进行装包的代码:

 int  packtlv_temp(char *buf, int size)
 {
     unsigned short crc16=0;
     int     pack_len = 0;
     int     data_len = 0;
     int     ofset = 0;
     float   temp;
     char    datatime[32];
     int     i,j;
  
      if(!buf || size < TLV_MINI_SIZE)
      {
  
          printf("Invalid input adgument\n");
          return 0;
  
      }
           /*   Packet head */ 
      buf[ofset]=HEAD;
      ofset +=1;
  
       /*   Tag */ 
      buf[ofset]=TAG_TEMP;
      ofset +=1;
  
      /*   Length  */
      ds18b20_get_temperature(&temp);
      i=(int)temp; //整数部分
      j=(int) ((temp-i) *100);//小数部分
  
      data_len = 2;
      pack_len= data_len + TLV_FIXED_SIZE;
      buf[ofset]=pack_len;
      ofset +=1;
  
       /*   Value */
      buf[ofset]=i;
      ofset+=1;
      buf[ofset]=j;
      ofset+=1;
  
      /*   CRC  */
      crc16=crc_itu_t(MAGIC_CRC, buf, ofset);
      ushort_to_bytes(&buf[ofset], crc16);
      ofset +=2;
      return ofset;
 }

3.TLV的解包

lv报文的格式: [帧头] [Tag] [Length] [Value] [CRC校验和]
解包的过程相对复杂,我们首先判断是否为空,不为空再去找到 报文头(帧头) ,接着接着往下读到长度tlv_len,在判断整个数据的长度是否比最小长度还要小,满足条件之后,遍历整个接收到数据,一直找到头再开始解析,解析的时候千万别以为就不会出错了,还要判断减去头后的大小是否小于2,小于2说明数据不完整,然后用crc校验,校验正确说明数据没问题可以解析。

int unpack(char *buf,int bytes)
{
      int                 i;
      char                *ptr=NULL;
      int                 len;
      unsigned short      crc,val;
       
      float                 t=0.0;
      float                 n,m;

      if( !buf )
      {
          printf("Invailed input!\n");
          return 0;
      }


again:
     if( bytes<TLV_MINI_SIZE )   //数据长度太短
     {
         printf("buf 不完整\n");
         return bytes;
     }
    printf("buf is good!\n");
    
    for(i=0;i<bytes;i++)
    {
          if( (unsigned char)buf[i]!=PACK_HEADER )
          {                        
              if( bytes-i<2 )
              {
                  printf("can not find length...\n");  //剩下的数据不能读到tlv的长度
                  memmove(buf,&buf[i],bv-i);
                  return bytes -i;
               }
           
               ptr=&buf[i];
               len=ptr[2];
               printf("tlv length:%d\n",len);

               if(len < TLV_MIN_SIZE||tlv_len>TLV_MAX_SIZE )  //这一帧中(length)长度错误
               {
                  memmove(buf, &tlv_ptr[2], bytes-i-2) ;
                  bytes = bytes -i -2 ;
                  goto again;
               }
               printf("tlv_len is ture!\n");

               if(len > bytes - i)//如果tlv长度比剩下的数据长度还长
               {
                   printf("Error!\n");
                   memmove(buf, tlv_ptr, bytes-i) ;
                   return bytes - i ;
               }
     
               crc16 = crc_itu_t(MAGIC_CRC,(unsigned char*)ptr, len-2);                        
               val = bytes_to_ushort((unsigned char*)&ptr[len-2],2) ;
               if( crc!=crc16 ) // crc检验出错!
              {
                    printf("crc is not ture!\n");
                    memmove(buf, &ptr[len], bytes-i-len) ;                                          
                    bytes = bytes -i -len ;                               
                    goto again ;
               }
         
               m=ptr[3];
               n=((float)ptr[4])/100;
               temp= m+n;
               printf("Temperature is:%f\n",temp);

               memmove(buf,&tlv_ptr[tlv_len], bytes-i-tlv_len) ;//处理完正确的一帧之后将其移出数组
               bytes = bytes -i -tlv_len ;                        
               goto again ;
       }
   }
   return 0}

你可能感兴趣的:(TLV协议的装包与解包(C语言))