C语言实现TLV消息组成

  1. 前言
    最近做项目时,需要发送TLV格式的网络字节序,在网上搜多了很多有关TLV的文章,感觉有些不通用。于是通过自己的摸索与测试,终于通过自己的方法组起TLV消息,并通过socket发送出去。在这里,希望和大家交流一下有关TLV的知识,写的不好的地方,请指正。

  2. 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

到此为止,结束。

你可能感兴趣的:(数据结构,c语言)