TLV----Demo讲解
来源:互联网 发布:mysql sql union 编辑:程序博客网 时间:2024/04/18 04:19
接触过网络协议的人对TLV一定或多或少的知道.作为一种自定义应用层标准.
TLV使用十分广泛.他对数据封包有着很好的定义,简单实用.
TLV即Type-Length-Value.即我们每个封装成TLV包的数据都必须为其添加Type和Length字段
TLV示意图如下:
大家首先要区分数据包和数据报.本文的实例仅仅针对TLV数据包.
而并未添加注册一些控制信令和报头形成数据报,而其中实际的数据
有TLV包组成.
TLV数据包和数据报的关系可由下图表示:
此外,TLV本身有两种结构,一种是基本TLV结构,另外一种是嵌套TLV结构.而本文使用的是嵌套TLV结构.
基本TLV包:
嵌套TLV包:
本文使用嵌套TLV包.
几点说明:
编码方法:
1. 将类型type用htonl转换为网络字节顺序,指针偏移+4
2. 将长度length用htonl转换为网络字节顺序,指针偏移+4
3. 若值value数据类型为int、char、short,则将其转换为网络字节顺序,指针偏移+4;若值为字符串类型,写进后,指针偏移+length
解码方法:
1. 读取type 用ntohl转换为主机字节序得到类型,指针偏移+4
2. 读取lengh用ntohl转换为主机字节序得到长度;指针偏移+4
3. 根据得到的长度读取value,若value数据类型为int、char、short,用ntohl转换为主机字节序,指针偏移+4;若value数据类型为字符串类型,指针偏移+length
Type和Length的长度固定,一般那是2、4个字节(这里统一采用4个字节);
Value的长度有Length指定
Demo代码如下:
#include <stdio.h>#include <WinSock2.h>#include <string>#pragma comment(lib, "WS2_32")//定义枚举类型常量,来填充Tpye字段,其中emTlvNRoot填充根TLV包的Type//emTlvName字段用于填充子TLV字段中名字的Type字段.emTlvAge,emTlvColor类似//此类型字段是为了TLV包解码时识别到底是哪个TLV包.进而解析出对应的数据.enum emTLVNodeType{emTlvNNone = 0,emTlvNRoot,//根节点emTlvName,//名字emTlvAge,//年龄emTlvColor//颜色 1 白色 2 黑色};//定义要封装成TLV包的数据,包括名字,年龄,颜色。typedef struct _CAT_INFO{char szName[12];intiAge;int iColor;}CAT_INFO,*LPCAT_INFO;//此类为TLC类,其中有四个成员函数,WriteInt和Write是用于//把原始数据封装为TLV包然后存入内存区块.即TLV包编码过程//而ReadInt和Read用于把内存区块的TLV包解析出来.即为TLV包的解码过程class CTlvPacket{public:CTlvPacket(char *pBuf,unsigned int len): m_pData(pBuf),m_uiLength(len),m_pEndData(m_pData+len), m_pWritePtr(m_pData),m_pReadPtr(m_pData) { }~CTlvPacket() { }bool WriteInt(int data,bool bMovePtr = true){int tmp = htonl(data);return Write(&tmp,sizeof(int));}bool Write(const void *pDst,unsigned int uiCount){::memcpy(m_pWritePtr,pDst,uiCount);m_pWritePtr += uiCount;return m_pWritePtr < m_pEndData ? true : false;}bool ReadInt(int *data,bool bMovePtr = true){Read(data,sizeof(int));*data = ntohl(*data);return true;}bool Read(void *pDst,unsigned int uiCount){::memcpy(pDst,m_pReadPtr,uiCount);m_pReadPtr += uiCount;return m_pReadPtr < m_pEndData ? true : false;}private:char *m_pData;unsigned int m_uiLength;char *m_pEndData;char *m_pWritePtr;char *m_pReadPtr;};/*格式:root L1 VT L V T L V T L VL1 的长度即为“T L V T L V T L V”的长度*///此函数实现TLV编码过程int TLV_EncodeCat(LPCAT_INFO pCatInfo, char *pBuf, int &iLen){if (!pCatInfo || !pBuf){return -1;}CTlvPacket enc(pBuf,iLen);enc.WriteInt(emTlvNRoot);enc.WriteInt(20+12+12); //lengthenc.WriteInt(emTlvName);enc.WriteInt(12);enc.Write(pCatInfo->szName,12);enc.WriteInt(emTlvAge);enc.WriteInt(4);enc.WriteInt(pCatInfo->iAge);enc.WriteInt(emTlvColor);enc.WriteInt(4);enc.WriteInt(pCatInfo->iColor);iLen = 8+20+12+12;return 0;}//此函数实现TLV解码过程int TLV_DecodeCat(char *pBuf, int iLen, LPCAT_INFO pCatInfo){if (!pCatInfo || !pBuf){return -1;}CTlvPacket encDec(pBuf,iLen);int iType;int iSum,iLength;encDec.ReadInt(&iType);if (emTlvNRoot != iType){return -2;}encDec.ReadInt(&iSum);//通过判断Type头字段对TLV包进行解析while (iSum > 0){encDec.ReadInt(&iType);//读取主TLV包的type头encDec.ReadInt(&iLength);//读取主TLV包的length头switch(iType)//此时buff指针移动到子TLV包.并解析子TLV的type头字段{case emTlvName:encDec.Read(pCatInfo->szName,12);iSum -= 20;break;case emTlvAge:encDec.ReadInt(&pCatInfo->iAge);iSum -= 12; break;case emTlvColor:encDec.ReadInt(&pCatInfo->iColor);iSum -= 12;break;default:printf("TLV_DecodeCat unkonwn error. \n"); break;}}return 0;}//主函数int main(int argc, char* argv[]){int iRet, iLen;char buf[256] = {0};CAT_INFO cat; //cat为定义的原始数据包括name,age,colormemset(&cat,0,sizeof(cat));//cat结构体初始化//对cat对象赋值strcpy(cat.szName,"Tom");cat.iAge = 5;cat.iColor = 2;//实现对cat对象的编码,编码结果存储在buf中.iRet = TLV_EncodeCat(&cat,buf,iLen);//TLV编码成功与否的判断if ( 0 == iRet ){printf("TLV_EncodeCat ok, iLen = %d. \n",iLen);}else{printf("TLV_EncodeCat error \n");}//将cat结构置为0memset(&cat,0,sizeof(cat)); //TLV包解码过程,将解包后的数据存入cat结构体对象iRet = TLV_DecodeCat(buf,iLen,&cat);//输出解包后的结构体数据if ( 0 == iRet ){printf("TLV_DecodeCat ok, cat name = %s, age = %d, color = %d. \n",cat.szName,cat.iAge,cat.iColor);}else{printf("TLV_DecodeCat error, code = %d. \n", iRet);}int iWait = getchar();return 0;}
运行结果截图如下:
这里要对TLV包长:iLen = 8+20+12+12; 进行说明.
为什么是这样呢.
因为一个完整的TLV包的主包包含Type字段和Length字段,每个字段占用4个字节所以共八个字节.
而主TLV包的Value字段包含三个子TLV包.
第一个子TLV包为name,而char szName[12],加之子包Type和子包Length,所以一共20个字节
同理,对于age子包共计八个字节,color子包共计八个字节.
所以整个TLV包的长度就为8+20+12+12
本文参考自博客:http://blog.csdn.net/chexlong/article/details/6974201
转载请注明作者:小刘
- TLV----Demo讲解
- 使用SuperSocket实现TLV自定义协议网络通信的Demo
- webpack demo 讲解
- Vuex Demo 讲解
- SDL系列讲解(四) demo讲解
- TBB parallel_while 使用 demo讲解
- cocos2d-x box2d Demo讲解
- TLV 协议
- TLV@C
- tlv解析
- TLV编码
- TLV基础
- TLV协议
- ListView嵌套ViewPager的小demo讲解
- Demo讲解之Lua和C++牵手
- reactNative小demo讲解 对比iOS
- JSONP 的工作原理,JSONP Demo讲解
- htc Vive VR扔小球Demo讲解
- poj 3041 Asteroids
- Python八荣八耻
- HDU 1735 字数统计
- 练习题
- asp.net微信公众平台开发(3)微信消息封装及反射赋值
- TLV----Demo讲解
- java bitSet的学习
- 重构Button类,实现APP在大屏幕下用遥控器遥控,界面按钮在获取焦点下显示边框
- POJ 1080 Humman Gene Function
- 64、使用jQuery全局函数转换数组
- document.createElement()的用法
- hdu 2063 过山车
- poj 1274The Perfect Stall
- html,css等入门