网络通信协议TLV解析器

来源:互联网 发布:ai如何画矩阵圆点 编辑:程序博客网 时间:2024/05/03 02:32


/*
* Copyright (c) 2005-2010 Tony Zhengjq <zhengjq@163.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
*    derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//tlv协议
#ifndef _TLV_H_
#define _TLV_H_

#pragma warning(disable: 4018 4244)

#ifndef int64_t
#define int64_t   long long
#endif

#ifndef uint64_t
#define uint64_t  unsigned long long
#endif

// host long 64 to network
static uint64_t hl64ton(uint64_t host)
{
 uint64_t   ret = 0;  
 unsigned long high,low;
 low = host & 0xFFFFFFFF;
 high = (host >> 32) & 0xFFFFFFFF;
 low = htonl(low);
 high = htonl(high);
 ret = low;
 ret <<= 32;
 ret |= high;
 return ret;
}

//network to host long 64
static uint64_t ntohl64(uint64_t host)
{
 uint64_t ret = 0;
 unsigned long high,low;
 low = host & 0xFFFFFFFF;
 high =  (host >> 32) & 0xFFFFFFFF;
 low = ntohl(low);
 high = ntohl(high);
 ret = low;
 ret <<= 32;
 ret |= high;
 return ret;
}

namespace TLV
{
 //分配内存部件
 template <class _L>
 class alloc_block
 {
 public:
  alloc_block(void* v, _L n) :_n(n) { _v = malloc(_n + 1); memcpy(_v, v, _n); ((char*)_v)[_n] = 0;}
  ~alloc_block() { free(_v); }
  static bool alloc() {return true;}
  void* _v; _L _n;
 };

 //不分配内存部件
 template <class _L>
 class block
 {
 public:
  block(void* v, _L n) :_n(n), _v(v){}
  ~block() {}
  void* _v; _L _n;
 };

 template <class _T, class _L, class _BLOCK> 
 class container
 {
 public:
  class object
  {
  public:
   void append(void* v, _L n)
   {
    _v.push_back(new _BLOCK(v, n));
   }

   ~object()
   {
    while (!_v.empty())
    {
     delete (*_v.begin());
     _v.erase(_v.begin());
    }
   }

   void* to_buffer(_L& len, int n)
   {
    if (_v.size() > n)
    {
     len = _v[n]->_n;
     return _v[n]->_v;
    }
    return NULL;
   }
  private:
   vector<_BLOCK*> _v;
  };

  typedef map<_T, object*> M;
 public:
  container(){}
  ~container() { clear(); }
 private:
  container(container& o);
  container& operator = (container& o);
 public:
  void clear()
  {
   while (!m_value.empty())
   {
    delete m_value.begin()->second;
    m_value.erase(m_value.begin());
   }
  }

  void free_object(container* tlv)
  {
   delete tlv;
  }

  bool empty(_T cmd)
  {
   return m_value.find(cmd) == m_value.end();
  }

 public: //压入数据

  void push_ex(_T cmd, const char * v)
  {
   push(cmd, v, strlen(v));
  }

  void push_ex(_T cmd, const string& v)
  {
   push(cmd, v.c_str(), v.length());
  }

  void push(_T cmd, char v)
  {
   push(cmd, &v, sizeof(v));
  }

  void push(_T cmd, unsigned char v)
  {
   push(cmd, &v, sizeof(unsigned char));
  }

  void push(_T cmd, short v)
  {
   v = htons(v);
   push(cmd, &v, sizeof(v));
  }

  void push(_T cmd, unsigned short v)
  {
   v = htons(v);
   push(cmd, &v, sizeof(v));
  }

  void push(_T cmd, int v)
  {
   v = htonl(v);
   push(cmd, &v, sizeof(v));
  }

  void push(_T cmd, unsigned int v)
  {
   v = htonl(v);
   push(cmd, &v, sizeof(v));
  }

  void push(_T cmd, long v)
  {
   v = htonl(v);
   push(cmd, &v, sizeof(v));
  }

  void push(_T cmd, unsigned long v)
  {
   v = htonl(v);
   push(cmd, &v, sizeof(v));
  }

  void push(_T cmd, int64_t v)
  {
   v = hl64ton(v);
   push(cmd, &v, sizeof(v));
  }

  void push(_T cmd, uint64_t v)
  {
   v = hl64ton(v);
   push(cmd, &v, sizeof(v));
  }


  void push(_T cmd, const string& v)
  {
   push(cmd, (void*)v.c_str(), v.length() + 1);
  }

  void push(_T cmd, const char* v)
  {
   push(cmd, (void*)v, strlen(v) + 1);
  }

  void push(_T cmd, container* object)
  { 
   char buffer[32*1024];
   int len = sizeof(buffer);
   object->encode(buffer, len);
   push(cmd, buffer, (_L)len);
  }

  void push(_T cmd, const char* v, int n)
  {
   push(cmd, (void*)v, n);
  }

  void push(_T cmd, unsigned char* v, int n)
  {
   push(cmd, (void*)v, n);
  }

  void push(_T cmd, void* v, int n)
  {
   //if (typeid(_BLOCK) == typeid(alloc_block<_L>))
   _BLOCK::alloc();
   pack_alloc_block(cmd, v, n);
  }
  
  void pack_block(_T cmd, void* v, int n)
  {
   if (n > 0) //空不压入
   {
    pack(cmd, v, n);
   }
   
  }

  void pack_alloc_block(_T cmd, void* v, int n)
  {
   if (n > 0) //空不压入
   {
    pack(cmd, v, n);
   }
  }

  void pack(_T cmd, void* v, int n)
  {
   typename M::iterator iter = m_value.find(cmd);
   if (iter != m_value.end())
   {
    iter->second->append(v, n);
   }
   else
   {
    object* value = new object;
    value->append(v, n);
    m_value.insert(make_pair(cmd, value));
   }
  }

 public: //获取数据
  
  void* to_buffer(_T cmd, _L& len, int n = 0)
  {
   typename M::iterator iter = m_value.find(cmd);
   if (iter != m_value.end())
    return iter->second->to_buffer(len, n);
   return NULL;
  }

  const char* to_string(_T cmd, int n = 0)
  {
   _L len = 0;
   const char* buffer = (const char*)to_buffer(cmd, len, n);
   if (buffer == NULL || len == 0)
    return "";

   if (buffer[len - 1] == '/0') //有 '/0'结束的处理
   {
    return buffer;
   }
   else       //没有'/0'结束处理
   {
    if (len >= sizeof(m_buffer))
    {
     return "";
    }

    memcpy(m_buffer, buffer, len);
    m_buffer[len] = 0;
    return m_buffer;
   }
    
  }
  

  uint64_t to_number(_T cmd, int n = 0)
  {
   _L len = 0;
   const char* buffer = (const char*)to_buffer(cmd, len, n);
   if (buffer == NULL)
    return 0;

   switch (len)
   {
   case 1:
    return (*(unsigned char*)buffer);
    break;
   case 2:
    return ntohs(*(unsigned short*)buffer);
    break;
   case 4:
    return ntohl(*(unsigned long*)buffer);
    break;

   case 8:
    return ntohl64(*(uint64_t*)buffer) ;
    break;
   default:
    return 0;
    break;
   }
  }
  
  container* to_object(_T cmd, int n = 0)
  {
   _L len = 0;
   char* buffer = (char*)to_buffer(cmd, len, n);

   if (buffer == NULL)
    return NULL;

   container* object = new container;

   object->decode(buffer, len);

   return object;
  }

  char to_int8(_T cmd, int n = 0)
  {
   return (char)to_number(cmd, n);
  }

  unsigned char to_uint8(_T cmd, int n = 0)
  {
   return (unsigned char)to_number(cmd, n);
  }

  short to_int16(_T cmd, int n = 0)
  {
   return (short)to_number(cmd, n);
  }

  unsigned short to_uint16(_T cmd, int n = 0)
  {
   return (unsigned short)to_number(cmd, n);
  }

  long to_int32(_T cmd, int n = 0)
  {
   return (long)to_number(cmd, n);
  }

  unsigned long to_uint32(_T cmd, int n = 0)
  {
   return (unsigned long)to_number(cmd, n);
  }

  int to_integer(_T cmd, int n = 0)
  {
   return (int)to_number(cmd, n);
  }

  int64_t to_int64(_T cmd, int n = 0)
  {
   return (int64_t)to_number(cmd, n);
  }

  uint64_t to_uint64(_T cmd, int n = 0)
  {
   return (uint64_t)to_number(cmd, n);
  }

 public:

  void decode(char* packet, int len)
  {
   int pos = 0;
   while (pos + sizeof(_T) + sizeof(_L) < len)
   {
    _T type = 0;
    _L length = 0;
    //T
    type = *(_T*)&packet[pos];
    type = inet_byte(type);
    pos += sizeof(_T);
    //L
    length = *(_L*)&packet[pos];
    length = inet_byte(length);
    pos += sizeof(_L);

    if (pos + length > len)
     break;
    //V
    pack(type, &packet[pos], length);
    pos += length;
    
   }
  }

  void encode(char* packet, int& len)
  {
   int length = 0;

   char* ptr = (char*)packet;
   for (typename M::iterator iter = m_value.begin(); iter != m_value.end(); ++iter)
   {
    int i = 0;
    do
    {
     _L n = 0;
     const char* v = (const char*)iter->second->to_buffer(n, i++);
     if (v == NULL)
      break;

     //T
     if (length + sizeof(iter->first) > len) return;
     length += pack_value(ptr, inet_byte(iter->first));
     

     //L
     if (length + sizeof(n) > len) return;
     length += pack_value(ptr, inet_byte(n));

     //V
     if (length + n > len) return;
     length += pack_value(ptr, (char*)v, n);

    } while (true);

    if (length > len) return;
   }

   len = length;
  }

 private:
   template <class T>
   T inet_byte(T _v)
   {
    switch (sizeof(T))
    {
    case 2:
     return (T)htons(_v);
     break;
    case 4:
     return (T)htonl(_v);
     break;
    default:
     return _v;
     break;
    }
   }

   template <class T>
   int pack_value(char*& ptr, T _v)
   {
    *(T*)ptr = _v;
    ptr += sizeof(T);
    return sizeof(T);
   }

   int pack_value(char*& ptr, const void* v, int n)
   {
    memcpy(ptr, v, n);
    ptr += n;
    return n;
   }
 private:
  M      m_value;
  char     m_buffer[1024];     //临时内存,主要处理字符串后没跟 "/0"解析符号的应用,多线程下需要注意。
 };
}

typedef TLV::alloc_block<unsigned long> alloc_block_uint32;
typedef TLV::block<unsigned long> block_uint32;

typedef TLV::alloc_block<unsigned short> alloc_block_uint16;
typedef TLV::block<unsigned short> block_uint16;

typedef TLV::alloc_block<unsigned char> alloc_block_uint8;
typedef TLV::block<unsigned char> block_uint8;

typedef TLV::container<unsigned long, unsigned long, alloc_block_uint32> tlv_44;
typedef TLV::container<unsigned long, unsigned long, block_uint32> tlv_44_analyze;

typedef TLV::container<unsigned short, unsigned long, alloc_block_uint32> tlv_24;
typedef TLV::container<unsigned short, unsigned long, block_uint32> tlv_24_analyze;

typedef TLV::container<unsigned short, unsigned short, alloc_block_uint16> tlv_22;
typedef TLV::container<unsigned short, unsigned short, block_uint16> tlv_22_analyze;

typedef TLV::container<unsigned char, unsigned short, alloc_block_uint16> tlv_12;
typedef TLV::container<unsigned char, unsigned short, block_uint16> tlv_12_analyze;

typedef TLV::container<unsigned char, unsigned char, alloc_block_uint8> tlv_11;
typedef TLV::container<unsigned char, unsigned char, block_uint8> tlv_11_analyze;

 


#endif //_TLV_H_

 

 

     TLV协议做为网络通信的一种伸缩协议,为广大用户所使用。TLV解析代码Google一大堆,都没有提出一套完整的解析方案。

  

     提出意见Bug

   

     mail:<zhengjq@163.com>
     msn:tony.zhengjq@hotmail.com

 

用例:

 

     TLV压入

 

       tlv_22  tlv_request;

       tlv_request.push(1, 100);

       tlv_request.push(2, "1231313");

       char szBuffer[1024];

       int nLen = 0;

       tlv_request.encode(szBuffer, nLen);

 

    TLV 解析

       tlv_22_analyze tlv_resp;

       tlv_resp.decode(szBuffer, nLen);

       printf("%d/r/n", tlv_resp.to_uint32(1));

       printf("%s/r/n", tlv_resp.to_string(2));

 

 

 

mail:<zhengjq@163.com>
msn:tony.zhengjq@hotmail.com

原创粉丝点击