|
TLV是一種可變格式,意思就是:
Type類型, Lenght長度,Value值;
Type和Length的長度固定,一般那是2、4個(gè)字節(jié)(這里統(tǒng)一采用4個(gè)字節(jié));
Value的長度有Length指定;
編碼方法:
1. 將類型type用htonl轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序,指針偏移+4
2. 將長度length用htonl轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序,指針偏移+4
3. 若值value數(shù)據(jù)類型為int、char、short,則將其轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序,指針偏移+4;若值為字符串類型,寫進(jìn)后,指針偏移+length
……繼續(xù)處理后面的tlv;
解碼方法:
1. 讀取type 用ntohl轉(zhuǎn)換為主機(jī)字節(jié)序得到類型,指針偏移+4
2. 讀取lengh用ntohl轉(zhuǎn)換為主機(jī)字節(jié)序得到長度;指針偏移+4
3. 根據(jù)得到的長度讀取value,若value數(shù)據(jù)類型為int、char、short,用ntohl轉(zhuǎn)換為主機(jī)字節(jié)序,指針偏移+4;若value數(shù)據(jù)類型為字符串類型,指針偏移+length
……繼續(xù)處理后面的tlv;
類型(Type)字段是關(guān)于標(biāo)簽和編碼格式的信息;
長度 (Length)字段定義數(shù)值的長度;
內(nèi)容(Value)字段表示實(shí)際的數(shù)值。
因此,一個(gè)編碼值又稱TLV(Type,Length,Value)三元組。編碼可以是基本型或結(jié)構(gòu)型,如果它表示一個(gè)簡單類型的、完整的顯式值,那么編碼就是基本型 (primitive);如果它表示的值具有嵌套結(jié)構(gòu),那么編碼就是結(jié)構(gòu)型 (constructed)。
下面是我寫的一個(gè)Demo程序:
- #include <stdio.h>
- #include <WinSock2.h>
- #include <string>
-
- #pragma comment(lib, "WS2_32")
-
- enum emTLVNodeType
- {
- emTlvNNone = 0,
- emTlvNRoot, //根節(jié)點(diǎn)
- emTlvName, //名字
- emTlvAge, //年齡
- emTlvColor //顏色 1 白色 2 黑色
- };
-
-
- typedef struct _CAT_INFO
- {
- char szName[12];
- int iAge;
- int iColor;
- }CAT_INFO,*LPCAT_INFO;
-
- 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 V
- T L V T L V T L V
-
- L1 的長度即為“T L V T L V T L V”的長度
-
- */
-
- 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); //根節(jié)點(diǎn)emTlvNRoot中的L,20=4+4+12,12=4+4+4,12=4+4+4
-
- enc.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; //總長度再加上emTLVNRoot的T和L,8=4+4
-
- return 0;
- }
-
- 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);
-
- while (iSum > 0)
- {
- encDec.ReadInt(&iType);
- encDec.ReadInt(&iLength);
- switch(iType)
- {
- 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;
- memset(&cat,0,sizeof(cat));
- strcpy(cat.szName,"Tom");
- cat.iAge = 5;
- cat.iColor = 2;
-
- iRet = TLV_EncodeCat(&cat,buf,iLen);
- if ( 0 == iRet )
- {
- printf("TLV_EncodeCat ok, iLen = %d. \n",iLen);
- }
- else
- {
- printf("TLV_EncodeCat error \n");
- }
-
- memset(&cat,0,sizeof(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;
- }
本Demo程序在VC2005環(huán)境下編譯通過,下面是運(yùn)行結(jié)果截圖

|