赞
踩
TLV协议是通信协议的一种,通讯协议就是指通信双方对数据传送控制的一种约定。 例如常见的TCP/IP、UDP协议等等都是通信协议。但是上述所提到的协议是不可以更改的。但是实际业务处理当中,我们在端对端通信时数据是不固定,所以我们希望可以让我们自定义的通信协议,它可以实现我们自己设定数据发送以及数据的封装形式,再通过上层的网络传输协议发送给对端,对端再根据自己定义好的协议对数据进行解析,从而得到想要的数据。TLV协议便是一种提供用户自定义的通讯协议*
数据的类型Tag(T) | 2字节 or 4字节 |
---|---|
数据的长度Length(L) | 2字节 or 4字节 |
数据的值Value(V) | 由length指定 |
它规定了一帧数据的前几个字节来表示数据类型,紧接着几个字节表示数据长度,最后是数据的内容。T
和 L
的长度固定,一般是2或4个字节,V
的长度由 Length
指定。
注意:字节序
字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。字节序一般分为大端和小端。 就是注意一下大小端存储
1、定义TLV数据类型
//自定义数据类型枚举
namespace TLVType
{
enum
{
TT_CHAR = 0, // C 8位字符
TT_SHORT, // h 16位整型
TT_INT32, // i 32位整型
TT_STRING, // s 0结尾的字符串
TT_COUNT,
};
}
typedef unsigned short TLVType_t; // tlv 类型
typedef unsigned short TLVLength_t; // tlv 长度
2、将数据TLV数据化
// 按format格式,从va_list中提取参数,进行序列化 bool TLVSerializer::Push(TLVType_t type, TLVLength_t length, const void *value) { if (type < TLVType::TT_CHAR || type >= TLVType::TT_COUNT) { return false; } if (m_size + (int)length > m_max_size) { return false; } //push 类型 int len = sizeof(TLVType_t); memcpy(m_buffer + m_size, &type, len); m_size += len; //push 长度 len = sizeof(TLVLength_t); memcpy(m_buffer + m_size, &length, len); m_size += len; //push 数据 memcpy(m_buffer + m_size, value, length); m_size += length; return true; } bool TLVSerializer::Pushf(const char* format, ...) { va_list v; va_start(v, format); bool ret = Pushv(format, v); va_end(v); return ret; } bool TLVSerializer::Pushv(const char* format, va_list v) { const char *p = MakeTLV(this, format, v); return p != 0; } const char* MakeTLV(TLVSerializer* tlv, const char* format, va_list v) { const char* p = format; for ( ; *p != 0; p++) { bool ret = false; switch (*p) { case 'c': { unsigned char c = va_arg(v, int); ret = tlv->Push(TLVType::TT_CHAR, sizeof(char), &c); } break; case 'h': { short c = va_arg(v, int); ret = tlv->Push(TLVType::TT_SHORT, sizeof(short), &c); } break; case 'i': { int c = va_arg(v, int); ret = tlv->Push(TLVType::TT_INT32, sizeof(int), &c); } break; case 's': { const char *c = va_arg(v, const char*); ret = tlv->Push(TLVType::TT_STRING, strlen(c)+1, c); } break; default: break; } if (!ret) return 0; } return p; }
3、将数据TLV反序列化
// 按format格式,进行反序列化,将提取的参数放入va_list中 bool TLVUnserializer::Pop(TLVType_t type, const void *value) { if (type < TLVType::TT_CHAR || type >= TLVType::TT_COUNT) { return false; } // pop 类型 int len = sizeof(TLVType_t); TLVType_t pop_type; memcpy(&pop_type, m_cur_ptr, len); if (pop_type != type) { return false; } // pop 长度 m_cur_ptr += len; len = sizeof(TLVLength_t); TLVLength_t length; memcpy(&length, m_cur_ptr, len); if (length <= 0 || length >= m_size) { return false; } // pop 数据 m_cur_ptr += len; memcpy((char*)value, m_cur_ptr, length); m_cur_ptr += length; return true; } bool TLVUnserializer::Popf(const char* format, ...) { va_list v; va_start(v, format); bool ret = Popv(format, v); va_end(v); return ret; } bool TLVUnserializer::Popv(const char* format, va_list v) { const char* p = PopTLV(this, format, v); return p != 0; } const char* PopTLV(TLVUnserializer* tlv, const char* format, va_list v) { const char* p = format; for ( ; *p != 0; p++) { bool ret = false; switch(*p) { case 'c': { unsigned char *c = va_arg(v, unsigned char*); ret = tlv->Pop(TLVType::TT_CHAR, c); } break; case 'h': { short *c = va_arg(v, short*); ret = tlv->Pop(TLVType::TT_SHORT, c); } break; case 'i': { int *c = va_arg(v, int*); ret = tlv->Pop(TLVType::TT_INT32, c); } break; case 's': { const char **c = va_arg(v, const char**); ret = tlv->Pop(TLVType::TT_STRING, c); } break; default: break; } if (!ret) return 0; } return p; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。