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

本文介绍了TLV(Tag-Length-Value)协议的基本概念,包括其报文格式和在数据传输中防止错误的方法。通过在字节流末尾添加CRC校验来确保数据的完整性。接着详细讲解了TLV的封包和解包过程,封包涉及如何将数据转换为TLV格式,而解包则阐述了如何从接收到的字节流中正确解析出TLV元素,包括校验CRC以验证数据准确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.TLV简介

TLV :即Tag(Type)-Length-Value,它包含三个域,第一个Tag为要封装的数据的类型域,第二个Length为封装的总的数据长度,第三个Value为要装入数据的值。其实就是一个简单的自定义通信协议,将要传送的数据进行编码组织将其发送出去的过程。
在这里插入图片描述
这是基本的tlv报文格式,在实际应用中我们可能会碰见在传输过程中数据发生跳变,这时候我们需要在一个字节流末尾加一个CRC校验,传输前算一下字节流的大小,传输到另外一个端口后再算一下,对比前后两个CRC的值,如果相同,表示没有发生字节跳变,反之,则舍弃。
加工后tlv报文:
在这里插入图片描述
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 
<think>好的,用户想找关于数据传输网关数据采集终端之间自定义通信协议的程序设计方法或示例代码。首先,我需要回顾之前的引用内容。引用1提到嵌入式系统中的通信协议分为并行和串行,而用户的问题涉及自定义协议,这通常属于串行通信,比如UART、SPI、I2C或者LoRa这样的无线技术。引用3提到了LoRa技术、Raspberry Pi硬件以及边缘计算架构,这可能和网关终端的设计相关。 接下来,用户可能需要了解自定义协议的设计步骤,比如帧结构定义、校验机制、数据编解码等。示例代码方面,可能需要用Python或C语言,因为引用2中的示例用了Python的requests库,可能用户对Python比较熟悉。 另外,用户可能需要考虑通信的可靠性,比如重传机制和超时处理,这在引用3的边缘计算延迟优化中有提到。还要注意硬件选择,比如使用树莓派作为网关,结合LoRa模块进行通信,这需要参考引用3中的硬件生态部分。 需要确认是否要含具体的代码示例,比如数据解包的函数,以及使用socket或串口通信的例子。同时,考虑数据加密和身份验证,提升安全性。可能还需要提到协议设计的灵活性,比如可扩展的帧结构,以适应不同的数据类型。 最后,生成相关问题,帮助用户深入理解协议设计中的各个关键点,比如帧结构设计、校验方法、硬件选型等。确保回答结构清晰,分步骤说明设计方法,并提供示例代码和优化建议。</think>### 数据传输网关数据采集终端的自定义通信协议设计方法 #### 一、协议设计核心要素 1. **帧结构定义** - 典型帧结构:`帧头 | 设备ID | 命令字 | 数据长度 | 载荷数据 | 校验码 | 帧尾` - 示例:$$ \text{0xAA55}[4B] | \text{DeviceID}[2B] | \text{CMD}[1B] | \text{DataLen}[2B] | \text{Payload}[nB] | \text{CRC16}[2B] | \text{0x55AA}[4B] $$ 2. **校验机制** - 常用CRC16或异或校验,例如: ```python def crc16(data: bytes) -> int: crc = 0xFFFF for byte in data: crc ^= byte << 8 for _ in range(8): crc = (crc << 1) ^ 0x1021 if (crc & 0x8000) else crc << 1 return crc & 0xFFFF ``` 3. **数据编解码** - 二进制协议推荐使用`struct`库打(Python)或内存直接映射(C) #### 二、程序设计示例(Python伪代码) ```python # 数据采集终端发送模块 import serial def send_sensor_data(device_id, temperature, humidity): frame_header = b'\xAA\x55\xAA\x55' cmd = 0x01 # 数据上报指令 payload = struct.pack('>ff', temperature, humidity) # 大端浮点数 crc = crc16(payload) packet = struct.pack(f'>4sHBI{len(payload)}sH4s', frame_header, device_id, cmd, len(payload), payload, crc, b'\x55\xAA\x55\xAA') ser = serial.Serial('/dev/ttyUSB0', 115200) ser.write(packet) # 网关接收解析模块 def parse_packet(data): if len(data) < 16: return None header, dev_id, cmd, dlen = struct.unpack('>4sHBI', data[:11]) payload = data[11:11+dlen] crc = struct.unpack('>H', data[11+dlen:13+dlen])[0] if crc16(payload) == crc: return {'dev_id':dev_id, 'data':struct.unpack('>ff', payload)} ``` #### 三、关键优化策略 1. **可靠性增强** - 添加ACK/NACK应答机制(超时重传) - 滑动窗口协议控制传输流量[^3] 2. **安全性设计** - 载荷数据AES加密 - 设备身份双向认证 3. **协议扩展性** - 采用TLV(Type-Length-Value)格式设计数据域 - 预留版本号字段支持协议升级 #### 四、硬件实现参考 - 网关端建议使用Raspberry Pi 4B(支持多线程处理)[^3] - 终端设备可采用STM32+LoRa模块实现低功耗远距离传输(SF12模式传输距离可达10km)[^3]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值