前言
最近做项目时,需要发送TLV格式的网络字节序,在网上搜多了很多有关TLV的文章,感觉有些不通用。于是通过自己的摸索与测试,终于通过自己的方法组起TLV消息,并通过socket发送出去。在这里,希望和大家交流一下有关TLV的知识,写的不好的地方,请指正。
TLV结构体
struct TLV_HEAD // tlv消息头
{
int length; // tlv消息总长度,即消息头和消息题总长度
short version; // 消息版本号
short commandID; // 命令类型
int seqence; // 消息序列号,从1开始递增
char checknum[16]; // 消息校验
};
struct TLV_BODY // tlv消息体
{
short type; // vale的类型,如int、double、string等
short value_length; // value的长度
char value[0]; // 消息体内容
};
上面结构体显示了TLV消息的结构类型,一个TLV消息是由消息头+消息体租成的,但是消息体是可变的。例如:
我需要发送三个数据,分别为int state = 2, char time[] = “201804271157”, int num = 12345;
那我们的TLV消息格式组成为(一个消息头+三个消息体):
TLV_HEAD + TLV_BODY(state) + TLV_BODY(time[]) + TLV_BODY(num)
3.组TLV消息代码
static int len = 0;
static int sequence = 0;
void makeTLVMessage(char *buf, short type, void *value)
{
short typeNetData = htons(type);
if(len == 0) // head
{
int length = 28;
short version = 2;
short commandID = 2;
//int sequence = 0;
char checknum[16] = {0};
int lengthNetData = htonl(length);
short versionNetData = htons(version);
short commandIDNetData = htons(commandID);
int sequenceNetData = htonl(sequence);
memcpy(buf + len, &lengthNetData, 4);
len += 4;
memcpy(buf + len, &versionNetData, 2);
len += 2;
memcpy(buf + len, &commandIDNetData, 2);
len += 2;
memcpy(buf + len, &sequenceNetData, 4);
len += 4;
memcpy(buf + len, checknum, 16);
len += 16;
sequence++;
}
if(type == 1) // string
{
char *str = (char *)value;
short str_Len = strlen(str);
short str_LenNetData = htons(str_Len);
printf("msg: %s\n", str);
memcpy(buf + len, &typeNetData, sizeof(type));
len += 2;
memcpy(buf + len, &str_LenNetData, sizeof(str_Len));
len += 2;
memcpy(buf + len, str, str_Len);
len += str_Len;
}
else if(type == 2) // int
{
int vl = *(int *)value;
short vl_Len = sizeof(vl);
short vl_LenNetData = htons(vl_Len);
int vlNetData = htonl(vl);
printf("msg: %d\n", vl);
memcpy(buf + len, &typeNetData, sizeof(type));
len += 2;
memcpy(buf + len, &vl_LenNetData, sizeof(vl_Len));
len += 2;
memcpy(buf + len, &vlNetData, vl_Len);
len += 4;
}
}
使用方法:首先定义一个len和sequence。len的作用记录指针偏移量,sequence记录消息序列号。
我们先将消息一个一个组进去,然后计算消息体的长度,最后填充消息的总长度。这里我们不考虑消息校验。
例如我们需要组一个TLV消息:int state = 2, char time[] = “201804271157”, int num = 12345;
typedef enum SQM_TLV_TYPE // 定义数据类型
{
TYPE_STRING = 1, // string型
TYPE_INT , // int型
TYPE_DOUBLE , // double型
}SQM_TLV_TYPE;
char buf[4096] = {0};
len = 0; // 初始化len
makeTLVMessage(buf, TYPE_INT, &state);
makeTLVMessage(buf, TYPE_STRING, time);
makeTLVMessage(buf, TYPE_INT, &num);
/* 最后我们需要讲TLV消息的总长度组进去 */
int tlvMsgNetData = htonl(len); // 消息的总长度
memcpy(buf, &tlvMsgNetData, 4);
通过socket将buf发送出去,我们得到的网络字节序为:00 00 00 3C 00 02 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 04 00 00 00 02 00 01 00 0C 32 30 31 38 30 34 32 37 31 31 35 37 00 02 00 04 00 00 30 39
到此为止,结束。