//Packet.h
#include "InetAddr.h" //对socket地址操作封装的类,比如char*IP转成ULONG
#include <vector>
using namespace std;
//先定义包头
typedef struct _HeadExt
{
//每帧所有分片公用信息
char flag[5]; //可以任意字符或数字或其他方法,用来标志我们发送的数据
UINT m_nSeqNumber; //本帧序数
USHORT m_nTotalFragment; //本帧数据可分成的总片数
USHORT m_nTotalSize; //本帧数据总长度
//每片各自信息
USHORT m_nFragmentIndex; //每帧分片序数,0 1 2 ... ,/
USHORT m_usPayloadSize; //本片数据长度
USHORT m_usFragOffset; //本片数据相对总数据的偏移量
USHORT m_bLastFragment; //是否最后一帧
//上 述数据有些重复,可以精简,有时间再修改
}HeadExt;
//从socket接收到的数据
class PacketIn
{
public :
PacketIn(char* lpszBuffer=NULL, UINT usBufferSize=0, UINT nDataSize=0);
virtual ~PacketIn();
HeadExt head;
BYTE* m_lpszBuffer;
ULONG ip;
UINT port;
CVLInetAddr addr;
BOOL Normalize();
UINT m_nDataLen;
UINT m_usBufferSize;
};
//接收到数据后开始重组使用的一个中间缓冲区,多个PacketIn合成一个Packet
//发送时从一个Packet分割出多片,不过本程序里直接发送,没有封成Packet
class Packet
{
public:
enum { TIMEOUT_LOCKFRAGMENTS = 1000 };
Packet( );
~Packet();
void reset();
void Set(const CVLInetAddr& iaFrom, UINT nSeqNumber );
BOOL InsertFragment(PacketIn* const pFragment);
bool m_bUsed;
int recvedpacks;
int recvedbytes;
int seqnum;
BYTE* m_pBuffer;
//测试用程序,直接访问了类的变量,没有封装成函数。上述变量正常应该写成 SetXXX ,GetXXX
private:
BOOL IsFragComplete() const;
ULONG m_ip;
USHORT m_port;
UINT m_nSeqNumber;
vector<int> SeqNumberList;
};
//Packet.cpp
#include "Packet.h"
PacketIn::PacketIn(char* lpszBuffer/*=NULL*/, UINT usBufferSize/*=0*/, UINT nDataSize/*=0*/)
{
m_lpszBuffer = (BYTE*)lpszBuffer;
m_usBufferSize = usBufferSize; //数据最大长度,其实没什么用,已经设置了这个值最大为64000
m_nDataLen = nDataSize;
}
PacketIn::~PacketIn()
{
}
BOOL PacketIn::Normalize() //判断收到的数据是否有效
{
const USHORT usHeaderSize = sizeof(HeadExt);
if ( !m_lpszBuffer || m_usBufferSize < usHeaderSize )//没什么用
{
return FALSE;
}
HeadExt* pHeader = (HeadExt*)( m_lpszBuffer );
if ( pHeader->m_usPayloadSize != m_nDataLen - usHeaderSize )
{
return FALSE;
}
head = *pHeader;
if ( pHeader->m_usPayloadSize > 0 )
{
memmove( m_lpszBuffer, m_lpszBuffer + usHeaderSize, pHeader->m_usPayloadSize );
}
return TRUE;
}
/
//这里是重组数据的临时缓冲,只看这里必然迷惑,先看socket收数据那里,再回来查看
void Packet::Set( const CVLInetAddr& iaFrom, UINT nSeqNumber )
{
m_iaFrom = iaFrom;
m_nSeqNumber = nSeqNumber;
if(m_pBuffer)
delete []m_pBuffer;
}
void Packet::reset()
{
m_bUsed = false;
recvedpacks = 0;
seqnum = 0;
recvedbytes = 0;
m_pBuffer = NULL;
m_pBuffer = new BYTE[64000];
SeqNumberList.clear();
}
Packet::Packet()
{
//calculate the ttl
//m_nTTL = RUDP_REASSEMBLE_TIMEOUT*CRudpPeer::PR_SLOWHZ;
reset();
}
Packet::~Packet()
{
if(m_pBuffer)
delete []m_pBuffer;
}
BOOL Packet::InsertFragment(PacketIn* const pFragment)
{
int nSize = SeqNumberList.size();
for(int i = 0; i< nSize ;i ++)
{
if(nSize ==SeqNumberList[i] )//收到重复数据包
{
return FALSE;
}
}
SeqNumberList.push_back(pFragment->head.m_nFragmentIndex);
memcpy( m_pBuffer + pFragment->head.m_usFragOffset, pFragment->m_lpszBuffer, pFragment->head.m_usPayloadSize);
recvedbytes += pFragment->head.m_usPayloadSize;
recvedpacks++;
m_bUsed = true;
CString str;
str.Format("收到数据:m_nSeqNumber%d ,m_nTotalFragment %d,m_nFragmentIndex %d,m_usFragOffset %d,m_nTotalSize %d,recvedbytes %d/r/n",
pFragment->head.m_nSeqNumber,pFragment->head.m_nTotalFragment,pFragment->head.m_nFragmentIndex,pFragment->head.m_usFragOffset,pFragment->head.m_nTotalSize,pFragment->head.m_usPayloadSize);
OutputDebugString(str);
if(recvedbytes == pFragment->head.m_nTotalSize )
return TRUE;
return FALSE;
}
更多技术文章请参见我的个人网站:http://www.joyvc.cn