当前位置:首页>Linux>Linux应用开发之:socket通信TLV传输协议

Linux应用开发之:socket通信TLV传输协议

  • 2026-08-20 15:12:01
Linux应用开发之:socket通信TLV传输协议
  • 了解TLV协议

TLV :即Tag(Type)-Length-Value,它包含三个域,第一个Tag为要封装的数据的类型域,第二个Length为封装的总的数据长度,第三个Value为要装入数据的值。其实就是一个简单的自定义通信协议,将要传送的数据进行编码组织将其发送出去的过程。想要了解的更细致,建议自己可以百度搜索学习,这里就不细述了。下面就以一个例子说一下装包和解包。

数据装包

装包的过程其实很简单,只要将你的数据按照包头(PACK_HEADER)、Tag(Type)-Length-Value、校验和的顺序将每个字节按十六进制的形式装进去,形成一个字节流发送出去,如下图:

PACK_HEADER自己定义(我定义为0xFD),大小通常为一个字节;Tag也是自己定义,通常为一个字节;Length的大小要看你的数据所占用的字节大小,它的大小为包头大小+Tag大小+Length大小+校验和大小+数据字节大小,自身一般占用一个字节;crc校验和一般占两个字节。crc校验有兴趣可以自己学习,本人也不是很懂,用别人的源码。知道了怎么装包,下面来解释一下**为什么要加包头和校验和进去:**举一个例子,如果我们不加头和尾,要发送的数据为0x01 0x03 0x3c,接收端就会按照Tag(Type)-Length-Value顺序进行解析,知道数据的类型为01,长度为3,值为3c。但是发送的过程中也有可能数据丢失或者混入了其他数据,这时数据有可能会变为0x00  0x01 0x56 0x03 0x23,这时接收端按照之前的顺序解析就会出错,当我们加上头的时候,接收端解析的时候会先找到包头,然后按顺序解析,但是这样还是有出错的可能,但是加上crc校验和之后,crc根据接收到的数据计算出一个校验和,用来和装包装进去的校验和进行比较,如果相同说明这一帧数据正确,接收端才会开始解析数据,如果不正确就不解析。下面是我将获取到的温度进行装包的代码:

intpacktlv_temp(char *buf,int size,float temp){     unsigned short              crc16=0;     int                         packlen=0;     int                         ofset=0;     int                         data_len=2;     int                         i,j;     float                       a;     if( !buf || !temp || size<TLV_MIN_SIZE )     {         printf("Invalid input argumrnts\n");         return 0;     }     /*pack header*/     buf[ofset]=PACK_HEADER;     ofset+=1;     /*type*/     buf[ofset]=TAG_TEMP;     ofset+=1;     /*length*/     /*     if( sizeof(temp)<=size-TLV_FIXED_SIZE )     {         data_len=sizeof(temp);     }     else     {         data_len=size-TLV_FIXED_SIZE;     }     */     packlen=data_len+TLV_FIXED_SIZE;     printf("pack length:%d\n",packlen);     buf[ofset]=packlen;     ofset+=1;     i=(int)temp;/*整数部分*///printf("i=%d\n",i);     a=(temp-i)*100;/*小数部分*/     //printf("a=%f\n",a);     buf[ofset]=i;     ofset+=1;     buf[ofset]=a;     ofset+=1;     crc16 = crc_itu_t(MAGIC_CRC, buf, ofset);     ushort_to_bytes(&buf[ofset], crc16);     ofset += 2;     for(j=0;j<packlen;j++)     {         printf("0x%02x ",(unsigned char)buf[j]);     }     printf("\n");     return ofset; }

## 数据解析

解析的过程没有装包那么容易,逻辑性很强而且过程很复杂,建议自己先画一个流程图,搞清解包时所有可能的情况,再来写代码。解包时首先要判断接收到的数据是否为空,在判断整个数据的长度是否比最小长度还要小,满足条件之后开始寻找头,遍历整个接收到数据,一直找到头再开始解析,解析的时候千万别以为就不会出错了,还要判断减去头后的大小是否小于2,小于2说明数据不完整,然后用crc校验,校验正确说明数据没问题可以解析。大概流程就是这样,完整的过程看流程图,如有大佬发现不完整,欢迎指正,共同学习。流程图如下:

下面是代码:

intunpacktlv(char *buf,int bv){      int                   i;      int                   tlv_len;      char                  *ptr=NULL;      float                 t=0.0;      float                 n,m;      unsigned short        crc16;      unsigned short        crc;      if( !buf )      {          printf("Invailed input!\n");          return 0;     }     if( buf==NULL )     {         printf("buf is NULL!\n");         return 0;     }     printf("buf is not NULL\n");go_on:     if( bv<TLV_MIN_SIZE )     {         printf("buf 不完整\n");         return bv;     }     printf("buf is good!\n");     for(i=0;i<bv;i++)     {          if( (unsigned char)buf[i]!=PACK_HEADER )         {             continue ;         }         printf("\nFind header!\n");         if( bv-i<2 )         {             printf("can not find length...\n");             memmove(buf,&buf[i],bv-i);             bv=bv-i;             goto go_on;         }         ptr=&buf[i];         tlv_len=ptr[2];         printf("tlv length:%d\n",tlv_len);         if( tlv_len<TLV_MIN_SIZE || tlv_len>TLV_MAX_SIZE )         {             printf("tlv_len is error!\n");             memmove(buf,&ptr[2+1],bv-i-2);             bv=bv-i-2;             goto go_on;         }         printf("tlv_len is ture!\n");         if( tlv_len>bv-i )         {             printf("Error!\n");             memmove(buf,ptr,bv-i);             return bv-i;         }         crc16=crc_itu_t(MAGIC_CRC,(unsigned char*)ptr, tlv_len-2);         crc=bytes_to_ushort((unsigned char*)&ptr[tlv_len-2],2) ;         if( crc!=crc16 )         {             printf("crc is not ture!\n");             memmove(buf,&ptr[tlv_len],bv+tlv_len);             bv=bv+tlv_len;             goto go_on;         }         printf("crc is true!\n");        m=ptr[3];        n=((float)ptr[4])/100;        //printf("%d\n",ptr[4]);        //printf("0x%02x \n",(unsigned char)ptr[4]);        t=m+n;         printf("Temperature is:%f\n",t);         printf("\n");         memmove(buf,&ptr[tlv_len],bv-i-tlv_len);         bv=bv-i-tlv_len;         goto go_on;     }     return 0;}

最新文章

随机文章