这个类是在我原来的项目经理写的代码基础上改进而成,在此对他表示诚挚的感谢。好,这个类的作用就是在网络传送的时候,给外部提供一个简单的处理数据方式,如果你的数据都很小,比如都是int8或者int16类型的东西,那我建议你不要用这个了,因为冗余太大(当然如果你的带宽很大,不在乎冗余的话尽管用,还是很方便的),对于每个数据对象有个标签,对于一个包的头尾也有标签,对象标签标志这个数据是什么类型,包标签标志这个类的大小,每个标签是4个字节,一个字节表示类型,其余3个字节表示长度,如果你的包大于16777216字节就不能用这个类了,要做修改才行,这个类的好处就是使用起来比较简单。大家的支持是我的动力!
/////////////////////////////////////////H//////////////////////////////////////////////
#ifndef LGLIB_PACKET_H
#define LGLIB_PACKET_H
#if _MSC_VER > 1000
#pragma once
#endif
#include <string>
using namespace std;
namespace lglib
{
#define MAX_PACKET_SIZE 2097152// 1024*1024*2 //the max data length
//datatype defination
typedef enum _PACKETTAGTYPE
{
UINT8 = 0, //int8
UINT16, //int16
UINT32, //int32
STRING, //string
STRUCT, //struct
PDATA, //pure data ,you can convert to anything
PacketHead, //Packet Head Tag
PacketEnd, //Packet End Tag
UnKnownType,//type error
Exceed //exceed the buffer
} PacketTagType;
//建立包头
#define MAKEPACKETTAG(HI,LOW) \
( (uint32) ( ( ( (uint8) HI ) << 24 ) | LOW ) )
#define GETTYPE(x) \
( (PacketTagType) ( x >> 24 ) )
#define GETVAL(x) \
( (uint32) ( ( x << 8 ) >> 8 ) )
/************************************************************************/
/* 注意!!!:包最大定义为2M,不能超过此大小 */
/* Attention!!!:The Max Packet size is 2M,Do not exceed this value! */
/************************************************************************/
/************************************************************************/
/* 数据包基类 */
/* Packet Base Class */
/************************************************************************/
class lg_Packet
{
public:
virtual cpstr GetData() = 0; // 获得数据
virtual uint32 GetTotalSize() = 0; // 获得包的实际大小
virtual void Reset() = 0; // 重置
};
/************************************************************************/
/* 数据包流入虚基类 : 处理已有的数据缓冲区 */
/************************************************************************/
class lg_InPacket
: public lg_Packet
{
public:
virtual lg_InPacket& operator>>( uint8& byte ) = 0;
virtual lg_InPacket& operator>>( uint16& word ) = 0;
virtual lg_InPacket& operator>>( uint32& dword ) = 0;
virtual lg_InPacket& operator>>( cpstr& cstr ) = 0;
virtual lg_InPacket& operator>>( string& str ) = 0;
virtual cpstr ReadData( uint32& size ) = 0;
virtual PacketTagType PreReadTag() = 0;
protected:
virtual uint32 ReadTag(PacketTagType type) = 0;
};
/************************************************************************/
/* 数据包流入实现类 : 处理已有的数据缓冲区 */
/************************************************************************/
class __LGLIB__ lg_DataInPacket : public lg_InPacket
{
protected:
// 数据
cpstr data; // 数据
int32 datalen; // 数据长度
cpstr cursor; // 指针
public:
// 构造
lg_DataInPacket( );
public:
// 方法
const char* GetData() { return data; }
uint32 GetTotalSize() { return datalen; }
virtual int32 SetData(cpstr d, int32 len);
void Reset();
virtual lg_InPacket& operator>>( uint8& byte );
virtual lg_InPacket& operator>>( uint16& word );
virtual lg_InPacket& operator>>( uint32& dword );
virtual lg_InPacket& operator>>( cpstr& cstr );
lg_InPacket& operator>>( string& str);
const void* ReadStruct(uint32& size);
const char* ReadData( uint32& size );
virtual bool IsEnd();
virtual PacketTagType PreReadTag();
protected:
virtual uint32 ReadTag(PacketTagType type);
};
/************************************************************************/
/* 数据包流出虚基类 : 生成新的数据缓冲区 */
/************************************************************************/
class lg_OutPacket
: public lg_Packet
{
public:
virtual lg_OutPacket& operator<<( uint8 byte ) = 0;
virtual lg_OutPacket& operator<<( uint16 word ) = 0;
virtual lg_OutPacket& operator<<( uint32 dword ) = 0;
virtual lg_OutPacket& operator<<( cpstr cstr ) = 0;
virtual lg_OutPacket& operator<<( const string& str ) = 0;
virtual void WriteData( cpstr Buf, uint32 size ) = 0;
private:
virtual void WriteTag(PacketTagType type,uint32 Len) = 0;
};
/************************************************************************/
/* 数据包流出实现类 : 生成新的数据缓冲区 */
/************************************************************************/
class __LGLIB__ lg_DataOutPacket :
public lg_OutPacket
{
protected:
// 数据
char* data; // 数据
char* cursor; // 指针
uint32 m_nTotalLen; // 整个缓冲长度
uint32 m_nIniSize;
public:
// 构造
lg_DataOutPacket();
//析构
~lg_DataOutPacket();
public:
//设定缓冲大小,默认申请2M
void InitData(uint32 IniSize = 0);
void Reset();
// 方法
//虚基类方法 :取得缓冲头指针
const char* GetData();
//虚基类方法 :取得缓冲数据大小
uint32 GetTotalSize();
lg_OutPacket& operator<<( const string& str )
{
return operator<<( str.c_str() );
}
virtual lg_OutPacket& operator<<( uint8 byte );
virtual lg_OutPacket& operator<<( uint16 word );
virtual lg_OutPacket& operator<<( uint32 dword );
virtual lg_OutPacket& operator<<( cpstr cstr );
virtual void WriteData( cpstr Buf, uint32 size );
virtual void WriteStruct(cpstr Buf,uint32 size);
private:
int32 SetCursor( int32 off );
void UpdateHead(uint32 size);
virtual void WriteTag(PacketTagType type,uint32 Len);
};
}
#endif
////////////////////////////////////////////////////////CPP////////////////////////////////////////////////
#include "stdafx.h"
#include "lg_Packet.h"
#include "lg_Exception.h"
//using namespace std;
namespace lglib
{
/************************************************************************/
/* CPP::lg_DataOutPacket */
/************************************************************************/
lg_DataOutPacket::lg_DataOutPacket()
: data(NULL) , cursor(NULL) ,m_nTotalLen(0),m_nIniSize(0)
{
}
lg_DataOutPacket::~lg_DataOutPacket()
{
delete [] data;
data = NULL;
cursor = NULL;
}
//构造之后必须调用此函数,否则无法正常运行
void lg_DataOutPacket::InitData(uint32 IniSize)
{
if(data != NULL){
delete [] data;
data = NULL;
cursor = NULL;
}
if(IniSize == 0){
data = new char[MAX_PACKET_SIZE];
m_nIniSize = MAX_PACKET_SIZE;
}else{
m_nIniSize = IniSize;
data = new char[IniSize + 1];//+ 1避免指向无效指针
}
cursor = data;
//数据长度的初始值
m_nTotalLen = sizeof(PacketTagType)*2;
WriteTag(PacketHead,m_nTotalLen);//cursor 移位
}
//虚基类方法 :取得缓冲头指针
const char* lg_DataOutPacket::GetData()
{
if(NULL == cursor)
throw lg_Exception("lg_DataOutPacket::GetData()","缓冲区未设置",LG_BUFFER_NOT_INIT);
return data;
}
//虚基类方法 :取得缓冲数据大小
uint32 lg_DataOutPacket::GetTotalSize()
{
if(NULL == cursor)
throw lg_Exception("lg_DataOutPacket::GetSize()","缓冲区未设置",LG_BUFFER_NOT_INIT);
return m_nTotalLen;
}
//给重复利用这个对象提供可能
void lg_DataOutPacket::Reset()
{
if(NULL == cursor)
throw lg_Exception("lg_DataOutPacket::SetCursor()","缓冲区未设置",LG_BUFFER_NOT_INIT);
cursor = data;
m_nTotalLen = sizeof(PacketTagType)*2;
WriteTag(PacketHead,m_nTotalLen);//cursor 移位
}
int32 lg_DataOutPacket::SetCursor( int32 off )
{
if(NULL == cursor)
throw lg_Exception("lg_DataOutPacket::SetCursor()","缓冲区未设置",LG_BUFFER_NOT_INIT);
int32 old = static_cast<int32>( cursor - data );
cursor = data + off;
return old;
}
void lg_DataOutPacket::UpdateHead(uint32 size)
{
uint32 dword = MAKEPACKETTAG(PacketHead,size);
*( uint32 *)data = htonl(dword);
}
//本类方法
void lg_DataOutPacket::WriteTag(PacketTagType type,uint32 Len)
{
char* EndPos = data + m_nIniSize;
// if(cursor > EndPos - sizeof( DataTag ))
// throw lg_Exception("void lg_DataOutPacket::WriteTag","无法容纳数据头",LG_BUFFER_LEN_LIMIT);
if ( cursor > EndPos - sizeof( int32 ) - Len)
throw lg_Exception("void lg_DataOutPacket::WriteTag","无法容纳数据内容",LG_BUFFER_LEN_LIMIT);
uint32 dword = MAKEPACKETTAG(type,Len);
*( uint32 *)cursor = htonl(dword);
if(type != PacketEnd){
cursor += sizeof(uint32);
if(type != PacketHead)
m_nTotalLen += sizeof(uint32);
}
}
lg_OutPacket& lg_DataOutPacket::operator <<( uint8 byte )
{
if(NULL == cursor)
throw lg_Exception("lg_DataOutPacket::operator <<( uint8 byte )","缓冲区未设置",LG_BUFFER_NOT_INIT);
WriteTag(UINT8,sizeof(byte));
*( uint8* )cursor = byte;
cursor += sizeof(byte);
m_nTotalLen+=sizeof(byte);
WriteTag(PacketEnd,m_nTotalLen);
UpdateHead(m_nTotalLen);
return (*this);
}
lg_OutPacket& lg_DataOutPacket::operator <<( uint16 word )
{
if(NULL == cursor)
throw lg_Exception("lg_DataOutPacket::operator <<( uint16 word )","缓冲区未设置",LG_BUFFER_NOT_INIT);
WriteTag(UINT16,sizeof(word));
*( uint16*)cursor = htons(word);
cursor += sizeof(word);
m_nTotalLen+=sizeof(word);
WriteTag(PacketEnd,m_nTotalLen);
UpdateHead(m_nTotalLen);
return (*this);
}
lg_OutPacket& lg_DataOutPacket::operator <<( uint32 dword )
{
if(NULL == cursor)
throw lg_Exception("lg_DataOutPacket::operator <<( uint32 dword )","缓冲区未设置",LG_BUFFER_NOT_INIT);
WriteTag(UINT32,sizeof(dword));
*( uint32 *)cursor = htonl(dword);
cursor += sizeof(dword);
m_nTotalLen+=sizeof(dword);
WriteTag(PacketEnd,m_nTotalLen);
UpdateHead(m_nTotalLen);
return (*this);
}
lg_OutPacket& lg_DataOutPacket::operator <<( cpstr cstr )
{
if(NULL == cursor)
throw lg_Exception("lg_DataOutPacket::operator <<( cpstr cstr )","缓冲区未设置",LG_BUFFER_NOT_INIT);
int32 len = static_cast<uint32>( strlen( cstr ) + 1 );
WriteTag(STRING,len);
strcpy( cursor, cstr );
cursor += len;
m_nTotalLen+=len;
WriteTag(PacketEnd,m_nTotalLen);
UpdateHead(m_nTotalLen);
return (*this);
}
void lg_DataOutPacket::WriteStruct(cpstr Buf,uint32 size)
{
if(NULL == cursor)
throw lg_Exception("lg_DataOutPacket::WriteData( cpstr Buf, int32 size )","缓冲区未设置",LG_BUFFER_NOT_INIT);
WriteTag(STRUCT,size);
memcpy( cursor, Buf, size );
cursor += size;
m_nTotalLen+=size;
WriteTag(PacketEnd,m_nTotalLen);
UpdateHead(m_nTotalLen);
}
void lg_DataOutPacket::WriteData( cpstr Buf, uint32 size )
{
if(NULL == cursor)
throw lg_Exception("lg_DataOutPacket::WriteData( cpstr Buf, int32 size )","缓冲区未设置",LG_BUFFER_NOT_INIT);
WriteTag(PDATA,size);
memcpy( cursor, Buf, size );
cursor += size;
m_nTotalLen+=size;
WriteTag(PacketEnd,m_nTotalLen);
UpdateHead(m_nTotalLen);
}
/************************************************************************/
/* CPP::lg_DataInPacket */
/************************************************************************/
lg_DataInPacket::lg_DataInPacket() : data(NULL),cursor(NULL),datalen(0)
{
}
bool lg_DataInPacket::IsEnd()
{
if(PreReadTag() == PacketEnd)
return true;
return false;
// const char* EndPos = data + datalen;
// if(cursor >= EndPos)
// return false;
// return true;
}
int32 lg_DataInPacket::SetData(cpstr d, int32 len)
{
data = cursor = d;
datalen = len;
//指定位置是否有开始标志
if(PreReadTag() != PacketHead){
data = cursor = NULL;
datalen = 0;
return 0;//抛弃此数据
}
uint32 BufLenHead = ReadTag(PacketHead);
//所提供的缓冲太小
if(len < BufLenHead){
data = cursor = NULL;
datalen = 0;
return -1;//缓冲不够,保留数据
}
cursor = data;
cursor = cursor + BufLenHead - sizeof(uint32);
//指定位置没有结束标志
if(PreReadTag() != PacketEnd){
data = cursor = NULL;
datalen = 0;
return 0;//抛弃此数据
}
uint32 BufLenEnd = ReadTag(PacketEnd);
//前后缓冲长度不一致
if(BufLenEnd != BufLenHead){
data = cursor = NULL;
datalen = 0;
return 0;//头尾不一致,抛弃数据
}
cursor = d + sizeof(uint32);
datalen = BufLenEnd;
return BufLenEnd;
}
void lg_DataInPacket::Reset()
{
data = cursor = NULL;
datalen = 0;
}
//预读类型并不改变cursor指针
PacketTagType lg_DataInPacket::PreReadTag()
{
if(NULL == cursor)
throw lg_Exception("lg_DataInPacket::PreReadTag()","缓冲区未设置",LG_BUFFER_NOT_INIT);
const char* EndPos = data + datalen;
if ( cursor <= EndPos - sizeof( uint32 ))
{
uint32 dword = ntohl( *( uint32* )cursor );
PacketTagType type = GETTYPE(dword);
if(type >= UINT8&&type < UnKnownType){
return type;
}else{
return UnKnownType;
}
}
return Exceed;
}
uint32 lg_DataInPacket::ReadTag(PacketTagType type)
{
if(NULL == cursor)
throw lg_Exception("lg_DataInPacket::ReadTag(PacketTagType type)","缓冲区未设置",LG_BUFFER_NOT_INIT);
const char* EndPos = data + datalen;
if ( cursor <= EndPos - sizeof( uint32 ))
{
uint32 dword = ntohl( *( uint32* )cursor );
PacketTagType dtype = GETTYPE(dword);
if(dtype != type)
throw lg_Exception("int32 lg_DataInPacket::ReadTag","类型不匹配",LG_TYPE_DISMATCH);
cursor += sizeof(uint32);
uint32 Len = GETVAL(dword);
if( Len <= 0 || Len >= MAX_PACKET_SIZE )
throw lg_Exception("int32 lg_DataInPacket::ReadTag","非法的数据长度",LG_BUFFER_TOO_LONG);
//头尾不做此判断
if(type != PacketHead && type != PacketEnd){
if(cursor > EndPos - Len)
throw lg_Exception("int32 lg_DataInPacket::ReadTag","无法容纳数据内容",LG_BUFFER_LEN_LIMIT);
}
return Len;
}else{
throw lg_Exception("int32 lg_DataInPacket::ReadTag","到达尾部",LG_BUFFER_LEN_LIMIT);
}
return 0;
}
lg_InPacket& lg_DataInPacket::operator >>( uint8& byte )
{
if(NULL == cursor)
throw lg_Exception("lg_DataInPacket::operator >>( uint8& byte )","缓冲区未设置",LG_BUFFER_NOT_INIT);
ReadTag(UINT8);
byte = *( uint8 *)cursor;
cursor += sizeof(byte);
return (*this);
}
lg_InPacket& lg_DataInPacket::operator >>( uint16& word )
{
if(NULL == cursor)
throw lg_Exception("lg_DataInPacket::operator >>( uint16& word )","缓冲区未设置",LG_BUFFER_NOT_INIT);
ReadTag(UINT16);
word = ntohs( *( uint16 *)cursor );
cursor += sizeof(word);
return (*this);
}
lg_InPacket& lg_DataInPacket::operator >>( uint32& dword )
{
if(NULL == cursor)
throw lg_Exception("lg_DataInPacket::operator >>( uint32& dword )","缓冲区未设置",LG_BUFFER_NOT_INIT);
ReadTag(UINT32);
dword = ntohl( *( uint32* )cursor );
cursor += sizeof(dword);
return (*this);
}
lg_InPacket& lg_DataInPacket::operator >>( cpstr& cstr )
{
if(NULL == cursor)
throw lg_Exception("lg_DataInPacket::operator >>( cpstr& cstr )","缓冲区未设置",LG_BUFFER_NOT_INIT);
int32 len = ReadTag(STRING);
if ( cursor <= data + datalen - len && !cursor[len - 1] )
{
cstr = cursor;
//memcpy(str,cursor,len);
cursor += len;
}
else
{
throw lg_Exception("lg_InPacket& lg_DataInPacket::operator >>( cpstr& str )","字符串尾错误",LG_STRING_END_ERROR);
}
return (*this);
}
lg_InPacket& lg_DataInPacket::operator >>( string& str )
{
cpstr p;
operator >>( p );
str = p;
return (*this);
}
const void* lg_DataInPacket::ReadStruct(uint32& size)
{
if(NULL == cursor)
throw lg_Exception("lg_DataInPacket::ReadData( int32& size )","缓冲区未设置",LG_BUFFER_NOT_INIT);
int32 len = ReadTag(STRUCT);
size = len;
const void * p = cursor;
cursor += len;
return p;
}
const char* lg_DataInPacket::ReadData( uint32& size )
{
if(NULL == cursor)
throw lg_Exception("lg_DataInPacket::ReadData( int32& size )","缓冲区未设置",LG_BUFFER_NOT_INIT);
int32 len = ReadTag(PDATA);
size = len;
const char * p = cursor;
cursor += len;
return p;
}
}