Linux 系统编程技巧与概念 第12章 基于 TLV 传输

本文详细介绍了TLVTypeLengthValue机制,用于解决不同系统间数据传输的兼容性问题。通过定义T(类型)、L(长度)和V(实际数据)三个字段,实现了跨平台的数据序列化和反序列化。文中还提供了示例代码展示如何进行TLV的解码、序列化和反序列化操作,强调避免使用系统依赖的数据类型,以确保数据一致性。
摘要由CSDN通过智能技术生成

TLV Type Length Value 机制

传统数据传输,不同情况下会容易做成数据收发错误

  1. 例如:不同系统 32 位元系统,16 位元系统 之间沟通,由于系统对 unsigned int 解释是不同,同一组数据在不同系统会出现不同结果
  2. 系统级别功能不同,导致数据结构差异,例如:系统 A 升级了,多支援2个数据,而系统 B,仍然是旧有结构

TLV 机制提出了解决方案

定义协议

T TLV Type (1 byte)
L Data Length (1 byte)
V Actual Data

例如:定义功能 A,用 132 代表
TLV Type 为 132 
Data Length 为 4 (单组数据)
Actual Data XXXXX

例子数据
132
20
201392385
24
234946817
24
218169601
24
184615169
24

注:上面例子是 ip/mask length e.g. 11.1.1.1/24 11.1.1.1 在 c 语言里用 int 表示

TLV 解码例子

void decode_tlv_132(char *tlv_ptr) {
    int tlv_type (int)*(tlb_ptr);
    tlv_ptr++;
    int data_length = (int)*(tlv_ptr);
    int unit_tlv_size = get_unit_size(tlv_type); // e.g. 4
    int i = 0;
    tlv_ptr++;
    char ip_address[4];
    switch(tlv_type) {
        case 132:
        {   
            int n_units = data_length/unit_tlv_size;
            for(i=0; i<n_units; i++) {
                #if 0
                unsigned int ip_address = *((unsigned int *)tlv_ptr);
                #endif
                memcpy(ip_address, tlv_ptr, 4); 
                tlv_ptr += 4;
                char mask = *tlv_ptr;
                tlv_ptr++;
            }   
        }   
        break;
        default:
        {   
            tlv_ptr += data_length;
        }   
        break;
    }   
}

重点

  • #if 0 是传统容易出错和不支援新功能地方
  • 使用 char 或 byte 不要使用基于系统的数据类型 例如: unsigned int
  • 上面 default: 是对新功能的支援

序列化和反序列化例子

对于 TLV 机制,提供了数据序列化和反序列化参考

序列化

typedef struct serialized_buffer {
    char *b;
    int size;
    int next;
} ser_buff_t;

void init_serialized_buffer(ser_buff_t **) {
    (*b) = (ser_buff_t *)calloc(1, sizeof(ser_buff_t);
    (*b)->b = calloc(1, SERIALIZE_BUFFER_DEFAULT_SZIE); // e.g. 100
    (*b)->size = SERIALIZE_BUFFER_DEFAULT_SIZE;
    (*b)->next = 0;
}

ser_buff_t *stream;
init_serialized_buffer(&stream);
void serialize_data(ser_buff_t *buff, char *data, int nbytes) {
    int available_size = buff->size - buff->next;
    char isResize = 0;

    while(available_size < nbytes) {
        buff->size = buff->size * 2;
        available_size = buff->size - buff->next;
        isResize = 1;
    }

    if(isResize == 0) {
        memcpy((char *)buff->b + buff->next, data, nbytes);
        buff->next += nbytes;
        return;
    }

    buff->b = realloc(buff->b, buff->size);
    memcpy((char *)buff->b + buff->next, data, nbytes);
    buff->next += nbytes;
    return;
}
  • buff 为缓存
  • buff->b 为当前位置
  • buff->next 为下一组数据位置
  • buff->size 为缓存大小

使用 序列化 例子

ser_buff_t *stream;
init_serialized_buffer(&stream);

char data = 132;
serialize_data(stream, &data, 1);

data = 20;
serialize_data(stream, &data, 1);

unsigned int ip = 201392385;
serialize_data(stream, &ip, 4);

char mask = 24;
serialize_data(stream, &mask, 1);

ip = 234946817;
serialize_data(stream, &ip, 4);

mask = 24;
serialize_data(stream, &mask, 1);

...

反序列化

void de_serialize_data(char *dest, ser_buff_t *b, int size) {
    memcpy(dest, b->b + b->next, size);
    b->next += size;
}

使用 反序列化 例子

unsigned int dest;
de_serialize_data((char *)&dest, b, 4);
  • b 为 例如:经过网络接收到的 buffer

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值