天天看點

【通信】TLV 格式及編解碼示例

轉載自:http://blog.csdn.net/chexlong/article/details/6974201

TLV是一種可變格式,意思就是:

Type類型, Lenght長度,Value值;

Type和Length的長度固定,一般那是2、4個位元組(這裡統一采用4個位元組);

Value的長度有Length指定;

編碼方法:

1.       将類型type用htonl轉換為網絡位元組順序,指針偏移+4

2.       将長度length用htonl轉換為網絡位元組順序,指針偏移+4

3.       若值value資料類型為int、char、short,則将其轉換為網絡位元組順序,指針偏移+4;若值為字元串類型,寫進後,指針偏移+length

……繼續處理後面的tlv;

解碼方法:

1.       讀取type 用ntohl轉換為主機位元組序得到類型,指針偏移+4

2.       讀取lengh用ntohl轉換為主機位元組序得到長度;指針偏移+4

3.       根據得到的長度讀取value,若value資料類型為int、char、short,用ntohl轉換為主機位元組序,指針偏移+4;若value資料類型為字元串類型,指針偏移+length

……繼續處理後面的tlv;

标簽(Tag)字段是關于标簽和編碼格式的資訊;

長度 (Length)字段定義數值的長度;

内容(Value)字段表示實際的數值。

是以,一個編碼值又稱TLV(Tag,Length,Value)三元組。編碼可以是基本型或結構型,如果它表示一個簡單類型的、完整的顯式值,那麼編碼就是基本型 (primitive);如果它表示的值具有嵌套結構,那麼編碼就是結構型 (constructed)。

下面是我寫的一個Demo程式:

[cpp]  view plain copy

  1. #include <stdio.h>  
  2. #include <WinSock2.h>  
  3. #include <string>  
  4. #pragma comment(lib, "WS2_32")  
  5. enum emTLVNodeType  
  6. {  
  7.     emTlvNNone = 0,  
  8.     emTlvNRoot,         //根節點  
  9.     emTlvName,          //名字  
  10.     emTlvAge,           //年齡  
  11.     emTlvColor          //顔色 1 白色 2 黑色  
  12. };  
  13. typedef struct _CAT_INFO  
  14. {  
  15.     char szName[12];  
  16.     int iAge;  
  17.     int iColor;  
  18. }CAT_INFO,*LPCAT_INFO;  
  19. class CTlvPacket  
  20. {  
  21. public:  
  22.     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) { }  
  23.     ~CTlvPacket() { }  
  24.     bool WriteInt(int data,bool bMovePtr = true)  
  25.     {  
  26.         int tmp = htonl(data);  
  27.         return Write(&tmp,sizeof(int));  
  28.     }  
  29.     bool Write(const void *pDst,unsigned int uiCount)  
  30.     {  
  31.         ::memcpy(m_pWritePtr,pDst,uiCount);  
  32.         m_pWritePtr += uiCount;  
  33.         return m_pWritePtr < m_pEndData ? true : false;  
  34.     }  
  35.     bool ReadInt(int *data,bool bMovePtr = true)  
  36.     {  
  37.         Read(data,sizeof(int));  
  38.         *data = ntohl(*data);  
  39.         return true;  
  40.     }  
  41.     bool Read(void *pDst,unsigned int uiCount)  
  42.     {  
  43.         ::memcpy(pDst,m_pReadPtr,uiCount);  
  44.         m_pReadPtr += uiCount;  
  45.         return m_pReadPtr < m_pEndData ? true : false;  
  46.     }  
  47. private:  
  48.     char *m_pData;  
  49.     unsigned int m_uiLength;  
  50.     char *m_pEndData;  
  51.     char *m_pWritePtr;  
  52.     char *m_pReadPtr;  
  53. };  
  54. int TLV_EncodeCat(LPCAT_INFO pCatInfo, char *pBuf, int &iLen)  
  55. {  
  56.     if (!pCatInfo || !pBuf)  
  57.     {  
  58.         return -1;  
  59.     }  
  60.     CTlvPacket enc(pBuf,iLen);  
  61.     enc.WriteInt(emTlvNRoot);  
  62.     enc.WriteInt(20+12+12); //length   
  63.     enc.WriteInt(emTlvName);  
  64.     enc.WriteInt(12);  
  65.     enc.Write(pCatInfo->szName,12);  
  66.     enc.WriteInt(emTlvAge);  
  67.     enc.WriteInt(4);  
  68.     enc.WriteInt(pCatInfo->iAge);  
  69.     enc.WriteInt(emTlvColor);  
  70.     enc.WriteInt(4);  
  71.     enc.WriteInt(pCatInfo->iColor);  
  72.     iLen = 8+20+12+12;  
  73.     return 0;  
  74. }  
  75. int TLV_DecodeCat(char *pBuf, int iLen, LPCAT_INFO pCatInfo)  
  76. {  
  77.     if (!pCatInfo || !pBuf)  
  78.     {  
  79.         return -1;  
  80.     }  
  81.     CTlvPacket encDec(pBuf,iLen);  
  82.     int iType;  
  83.     int iSum,iLength;  
  84.     encDec.ReadInt(&iType);  
  85.     if (emTlvNRoot != iType)  
  86.     {  
  87.         return -2;  
  88.     }  
  89.     encDec.ReadInt(&iSum);  
  90.     while (iSum > 0)  
  91.     {  
  92.         encDec.ReadInt(&iType);  
  93.         encDec.ReadInt(&iLength);  
  94.         switch(iType)  
  95.         {  
  96.         case emTlvName:  
  97.             encDec.Read(pCatInfo->szName,12);  
  98.             iSum -= 20;  
  99.             break;  
  100.         case emTlvAge:  
  101.             encDec.ReadInt(&pCatInfo->iAge);  
  102.             iSum -= 12;  
  103.             break;  
  104.         case emTlvColor:  
  105.             encDec.ReadInt(&pCatInfo->iColor);  
  106.             iSum -= 12;  
  107.             break;  
  108.         default:  
  109.             printf("TLV_DecodeCat unkonwn error. \n");  
  110.             break;  
  111.         }  
  112.     }  
  113.     return 0;  
  114. }  
  115. int main(int argc, char* argv[])  
  116. {  
  117.     int iRet, iLen;  
  118.     char buf[256] = {0};  
  119.     CAT_INFO cat;  
  120.     memset(&cat,0,sizeof(cat));  
  121.     strcpy(cat.szName,"Tom");  
  122.     cat.iAge = 5;  
  123.     cat.iColor = 2;  
  124.     iRet = TLV_EncodeCat(&cat,buf,iLen);  
  125.     if ( 0 == iRet )  
  126.     {  
  127.         printf("TLV_EncodeCat ok, iLen = %d. \n",iLen);  
  128.     }  
  129.     else  
  130.     {  
  131.         printf("TLV_EncodeCat error \n");  
  132.     }  
  133.     memset(&cat,0,sizeof(cat));  
  134.     iRet = TLV_DecodeCat(buf,iLen,&cat);  
  135.     if ( 0 == iRet )  
  136.     {  
  137.         printf("TLV_DecodeCat ok, cat name = %s, age = %d, color = %d. \n",cat.szName,cat.iAge,cat.iColor);  
  138.     }  
  139.     else  
  140.     {  
  141.         printf("TLV_DecodeCat error, code = %d. \n", iRet);  
  142.     }  
  143.     int iWait = getchar();  
  144.     return 0;  
  145. }  

本Demo程式在VC2005環境下編譯通過,下面是運作結果截圖

【通信】TLV 格式及編解碼示例

繼續閱讀