C:TLV消息编码及常用操作

/*
1、TLV简介:
在通信系统中,两个设备之前必然存在消息交互,消息的格式也存在各种编码类型,
本文仅描述TLV编码的消息格式。Type-length-value(TLV)格式中T、L的长度固定,
通常为1-8个4个字节,V的长度不固定,由L的值表示,V的内容也可以嵌套子TLV格式。
举例:假设消息按大端模式存放,T占4个字节,L占2个字节,下面的消息:
 unsigned char pMsg[] = {0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01,0x01,0x01, 0x01}
 T = {0x09, 0x00, 0x00, 0x00},值为9。
 L = {0x04, 0x00},值为4。
 V = {0x01,0x01,0x01, 0x01} ,长度为4,每个字节的值均为1。
2、代码实现:a、按T的值由小到大排序一个消息(假定消息中不存在T相同的信元);
             b、在两个消息中查找相同的信元(T、L、V)均相同,并输出信元个数。

作者:Socrates
日期:2014-08-05
*/

#include "stdafx.h"
#include <stdlib.h>
#include <memory.h>

#define TLV_T_LEN (4)
#define TLV_L_LEN (2)

/*错误码*/
enum _RetCode
{
    ERR = -1, /*失败*/
    OK = 0    /*成功*/
}RETCODE;

/*信元TLV结构*/
typedef struct _stIE
{
    unsigned int ulTag;    /*T*/
    unsigned short usLen;  /*L*/
    unsigned char *pValue; /*V*/
}IE;

/*消息链表*/
typedef struct _stMsg
{
    IE ie;
    struct _stMsg *pNext;
}Msg;

/*
功能:创建链表
*/
int CreateMsgList(Msg *&pList)
{
    pList = (Msg *)malloc(sizeof(Msg));
    if (NULL == pList)
    {
        return ERR;
    }
    memset(&(pList->ie), 0, sizeof(IE));
    pList->pNext = NULL;

    return OK;
}

/*
功能:销毁链表
*/
void DestoryMsgList(Msg *pList)
{
    if (NULL == pList)
    {
        return;
    }

    Msg *p = pList;
    while(NULL != p)
    {
        p = p->pNext;
        free(pList);
        pList = p;
    }
    free(pList);
    pList = NULL;
    return;
}

/*
功能:向消息链表中插入信元,并保持按Tag递增
*/
int InsertIEToMsgList(Msg *pMsgList, const IE *pIE)
{
    if ((NULL == pMsgList)
        || (NULL == pIE))
    {
        return ERR;
    }

    /*链表销毁时释放*/
    Msg *pInsertMsg = (Msg *)malloc(sizeof(Msg));
    if (NULL == pInsertMsg)
    {
        return ERR;
    }

    /*创建链表结点*/
    memcpy(&(pInsertMsg->ie), pIE, sizeof(IE));
    pInsertMsg->pNext = NULL;

    /*按Tag递增插入结点,保持链表有序,不带头结点*/
    Msg *p = pMsgList;
    while(NULL != p->pNext)
    {
        if ((p->pNext->ie.ulTag) > (pIE->ulTag))
        {
            break;
        }
        p = p->pNext;
    }

    pInsertMsg->pNext = p->pNext;
    p->pNext = pInsertMsg;

    return OK;
}

/*
功能:获取指定消息中的第一个信元
*/
IE *GetIEFromMsg(const unsigned char *pInMsg)
{
    if (NULL == pInMsg)
    {
        return NULL;
    }

    /*链表销毁时释放*/
    IE *pIE = (IE *)malloc(sizeof(IE));
    if (NULL == pIE)
    {
        return NULL;
    }
    memset(pIE, 0, sizeof(IE));

    pIE->ulTag = *(unsigned int *)pInMsg;
    pIE->usLen = *(unsigned short *)(pInMsg + TLV_T_LEN);
    pIE->pValue = (unsigned char *)(pInMsg + TLV_T_LEN + TLV_L_LEN);

    return pIE;
}

/*
功能:构造有序消息链表
*/
int CreateSortMsgList(unsigned char *pInMsg, unsigned int ulMsgLen, Msg *&pOutMsgList)
{

    if ((NULL == pInMsg)
        ||(0 == ulMsgLen))
    {
        return ERR;
    }

    /*建立链表*/
    if (ERR == CreateMsgList(pOutMsgList))
    {
        return ERR;
    }

    unsigned int iTmpMsgLen = 0;
    IE *pIE = NULL;

    /*遍历消息,注意获取信元并插入消息链表*/
    while(iTmpMsgLen < ulMsgLen)
    {
        pIE = GetIEFromMsg(pInMsg);
        if (NULL == pIE)
        {
            return ERR;
        }

        if(ERR == InsertIEToMsgList(pOutMsgList, pIE))
        {
            return ERR;
        }

        pInMsg += (TLV_T_LEN + TLV_L_LEN + pIE->usLen);
        iTmpMsgLen += (TLV_T_LEN + TLV_L_LEN + pIE->usLen);
    }    

    return OK;
}

/*
功能:消息排序
*/
int Sort(unsigned char *pInMsg, unsigned int ulMsgLen, unsigned char *pOutMsg)
{
    if ((NULL == pInMsg)
        || (NULL == pOutMsg)
        || (0 == ulMsgLen))
    {
        return ERR;
    }

    /*建立有序消息链表*/
    unsigned char *pTmp = pOutMsg;
    Msg *pMsgList = NULL;
    if (ERR == CreateSortMsgList(pInMsg, ulMsgLen, pMsgList))
    {
        DestoryMsgList(pMsgList);
        return ERR;
    }

    /*输出排序后的消息*/
    Msg *pList = pMsgList->pNext;
    while(NULL != pList)
    {
        memcpy(pTmp, &(pList->ie), TLV_T_LEN + TLV_L_LEN);
        memcpy(pTmp + TLV_T_LEN + TLV_L_LEN, pList->ie.pValue, pList->ie.usLen);
        pTmp += (TLV_T_LEN + TLV_L_LEN + pList->ie.usLen);
        pList = pList->pNext;
    }

    DestoryMsgList(pMsgList);
    return OK;
}

/*
功能:比较两个信元是否相同
*/
int IsSameIE(IE *pIE1, IE *pIE2)
{
    if ((NULL == pIE1)
        || (NULL == pIE2))
    {
        return ERR;
    }

    if ((pIE1->ulTag == pIE2->ulTag)
        && (pIE1->usLen == pIE2->usLen)
        && (0 == memcmp(pIE1->pValue, pIE2->pValue, pIE1->usLen)))
    {
        return OK;
    }

    return ERR;
}

/*
功能:比较两个消息,并输出相同信元个数
*/
int CompareMsg(unsigned char *pMsg1,
               unsigned int ulMsgLen1,
               unsigned char *pMsg2,
               unsigned int ulMsgLen2,
               unsigned int *ulSameNum)

{
    /*创建有序消息链表1*/
    Msg *pMsgList1 = NULL;
    if (ERR == CreateSortMsgList(pMsg1, ulMsgLen1, pMsgList1))
    {
        DestoryMsgList(pMsgList1);
        return ERR;
    }

    /*创建有序消息链表2*/
    Msg *pMsgList2 = NULL;
    if (ERR == CreateSortMsgList(pMsg2, ulMsgLen2, pMsgList2))
    {
        DestoryMsgList(pMsgList1);
        DestoryMsgList(pMsgList2);
        return ERR;
    }

    Msg *p = pMsgList1->pNext;
    Msg *q = NULL;
    unsigned int iCount = 0;

    /*比较消息*/
    while(NULL != p)
    {
        q = pMsgList2->pNext;
        while(NULL != q)
        {
            if (OK == IsSameIE(&(p->ie), &(q->ie)))
            {
                iCount++;
            }

            q = q->pNext;
        }
        p = p->pNext;
    }

    DestoryMsgList(pMsgList1);
    DestoryMsgList(pMsgList2);

    *ulSameNum = iCount;

    return OK;

}

int main(int argc, char* argv[])
{
    unsigned char pMsg[] = {0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01,0x01,0x01, 0x01,
                            0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02,0x02,0x02, 0x02, 0x02, 0x02, 0x02,
                            0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03,0x03,0x03, 0x03, 0x03,
                            0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01,0x01,0x01, 0x01,
                            0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08,0x08,
                            0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x09,0x09,0x09, 0x09};

    unsigned char pMsg2[] = {0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01,0x01,0x01, 0x01,
                            0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02,0x02,0x02, 0x02, 0x02, 0x02, 0x02,
                            0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03,0x03,0x03, 0x03, 0x03,
                            0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01,0x01,0x01, 0x01,
                            0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08,0x08,
                            0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x09,0x09,0x09, 0x09};
    int iLen = sizeof(pMsg) / sizeof(pMsg[0]);
    for (int i = 0; i < iLen; i++)
    {
        printf("0x%x,", pMsg[i]);
    }
    printf("\n\n");

    unsigned char *pSortMsg = (unsigned char *)malloc(iLen);
    if (NULL == pSortMsg)
    {
        return ERR;
    }

    if (ERR != Sort(pMsg, iLen, pSortMsg))
    {
        for (int i = 0; i < iLen; i++)
        {
            printf("0x%x,", pSortMsg[i]);
        }
    }

    int iLen2 = sizeof(pMsg2) / sizeof(pMsg2[0]);
    unsigned int iSameNum = 0;

    if (ERR != CompareMsg(pMsg, iLen, pMsg2, iLen2, &iSameNum))
    {
        printf("\nSame Number is %d", iSameNum);
    }

    getchar();
    return 0;
}

C:TLV消息编码及常用操作

时间: 2025-01-10 20:33:55

C:TLV消息编码及常用操作的相关文章

python MySQLdb 常用操作

我采用的是MySQLdb操作的MYSQL数据库.先来一个简单的例子吧: import MySQLdb try:     conn=MySQLdb.connect(host='localhost',user='root',passwd='root',db='test',port=3306)     cur=conn.cursor()     cur.execute('select * from user')     cur.close()     conn.close() except MySQL

WCF扩展之实现ZeroMQ绑定和protocolBuffer消息编码(三)实现ReplyChannel(2016-03-15 12:35)

这是这个系列的第三篇,其他的文章请点击下列目录 WCF扩展之实现ZeroMQ绑定和protocolBuffer消息编码(一)概要设计 WCF扩展之实现ZeroMQ绑定和protocolBuffer消息编码(二)实现IRequestChannel WCF扩展之实现ZeroMQ绑定和protocolBuffer消息编码(三)实现ReplyChannel 相对于RequestChannel,ReplyChannel比较复杂一些. 1 启动zmq的rep结点 首先需要重载OnOpen方法,启动zmq的r

OVS常用操作「转」

原文地址:http://www.cnblogs.com/puremans/p/6562392.html OVS常用操作: 1.添加网桥:ovs-vsctl add-br 交换机名 2.删除网桥:ovs-vsctl del-br 交换机名 3.添加端口:ovs-vsctl add-port 交换机名 端口名(网卡名) 4.删除端口:ovs-vsctl del-port 交换机名 端口名(网卡名) 5.连接控制器:ovs-vsctl set-controller 交换机名 tcp:IP地址:端口号 

javascript中字符串常用操作总结、JS字符串操作大全

字符串的操作在js中非常频繁,也非常重要.以往看完书之后都能记得非常清楚,但稍微隔一段时间不用,便会忘得差不多,记性不好是硬伤啊...今天就对字符串的一些常用操作做个整理,一者加深印象,二者方便今后温习查阅. String对象属性 (1) length属性 length算是字符串中非常常用的一个属性了,它的功能是获取字符串的长度.当然需要注意的是js中的中文每个汉字也只代表一个字符,这里可能跟其他语言有些不一样. var str = 'abc'; console.log(str.length);

MariaDB安装、初始化及常用操作

1.Linux(CentOS 7.2)下安装与初始化 #安装 yum install mariadb-server #设置编码 vim /etc/my.cnf [mysqld]character-set-server=utf8 #启动 systemctl start mariadb #自启动 systemctl enable mariadb #停止 systemctl stop mariadb #初始化 mysql_secure_installation 2.连接.查看用户.创建用户.授权 #连

安装SQLite及常用操作

SQLite是数据储存基础,今天我们就从SQLite开始讲起. 什么是SQLite SQLite是一款非常轻量级的关系数据库系统,支持多数SQL92标准.SQLite在使用前不需要安装设置,不需要进程来启动.停止或配置,而其他大多数SQL数据库引擎是作为一个单独的服务器进程,被程序使用某种内部进程通信(典型的是TCP/IP),完成发送请求到服务器和接收查询结果的工作,SQLite不采用这种工作方式.使用SQLite时,访问数据库的程序直接从磁盘上的数据库文件读写,没有中间的服务器进程.使用SQL

Ajax-04 jQuery Ajax 常用操作

jQuery jQuery 其实就是一个JavaScript的类库,其将复杂的功能做了上层封装,使得开发者可以在其基础上写更少的代码实现更多的功能. jQuery Ajax a.概述 jQuery 不是生产者,而是大自然的搬运工 jQuery Ajax 本质是 XMLHttpRequest 或 ActiveXObject b.使用 --- 下载导入jQuery(2.+ 版本不再支持IE9以下的浏览器) jQuery Ajax常用操作 jQuery.ajax( url [, settings ]

表单的常用操作

知识点: 表单是前后端数据交互的一种重要方式,使用js操作表单也是十分常见的.不过好像每次到表单操作我都要去查API,所以本次想对表单的常用操作做个小结,以备后面随时查看. 首先,我们要知道如下的一些知识: 1. 表单字段在向后台提交数据时,使用的是表单控件的name属性的value,与id无关.(大家可以在百度搜细说表单找到Fish Li大神的这篇文章看看) 2. 表单向服务端传数据时会经过编码.目前基本上只会只使用二种编码规则:application/x-www-form-urlencode

vim常用操作和使用技巧

vi是linux与unix下的常用文本编辑器,其运行稳定,使用方便,本文将分两部分对其常用操作技巧和配置进行阐述,其中参考了网上的一些文章,对作者表示感谢 PART1 操作技巧 说明: 以下的例子中 xxx 表示在命令模式下输入 xxx 并回车 以下的例子中 :xxx 表示在扩展模式下输入 xxx 并回车 ()中的命令表示相关命令.[]表示命令等同 在编辑模式或可视模式下输入的命令会另外注明. 移动光标 在 vi 中, 移动光标和编辑是两件事, 正因为区分开来, 所以可以很方便的进行光标定 位和