//***********************************************************************************
//文件说明:TSocket.h
//功能: 文件传输客户端实现头文件
//使用说明:使用TCP的IOCP实现,可以传送大消息包、文件,同一客户端可以同时发送多个文件
// 1、用TClients创建一个对象,pClients
// 2、调用pClients->CreateClient(...)函数,参数1、2是要连接的服务端IP和端口,
// 3服务端返回消息的事件回调处理函数,4是服务端断开连接的事件回调处理函数
// 3、调用pClients->SendMsg(...)给对端发消息
// 4、调用pClients->SendFile(...)给对端发文件
// 5、调用pClients->Disconnet(...)主动断开连接
// 6、销毁pClients对象
//时间: 2010.5.1 23:13:56
//作者: 废人
//留待实现:
// bool SendFileToAll(const char * filename);
// bool SendFileToServers(SOCKETS sClients,const char * filename);
// bool SendFileToOther(SOCKET ExceptSocket,char * pData,ULONG Length);
// bool SendMsgToAll(char * pData,ULONG Length);
// bool SendMsgToServers(SOCKETS sClients,char * pData,ULONG Length);
// bool SendMsgToOther(SOCKET ExceptSocket,char * pData,ULONG Length);
//***********************************************************************************
#if !defined(AFX_TSOCKET_H__46FFF420_23C3_4356_A88D_AEBDA61EA186__INCLUDED_)
#define AFX_TSOCKET_H__46FFF420_23C3_4356_A88D_AEBDA61EA186__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <list>
#include <afxtempl.h>
#include <winsock2.h>
#include <vector>
#include <queue>
#include <string>
#include <algorithm>
#include <map>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
#pragma warning(disable:4786)
//服务端口
#define SVRPORT 10012
//缓冲区大小
#define BUFFER_SIZE 4096
//接收数据
#define RECV_POSTED 0
//发送数据
#define SEND_POSTED 1
class TClient;
class TClients;
struct TPack;
//单句柄数据
typedef struct _PER_HANDLE_DATA
{
TClient *client;
}PER_HANDLE_DATA,*LPPER_HANDLE_DATA;
//IO操作数据
typedef struct _PER_IO_OPERATION_DATA
{
//重叠结构
OVERLAPPED OverLapped;
//数据缓冲区
WSABUF RecvDataBuf;
WSABUF SendDataBuf;
char RecvBuf[BUFFER_SIZE];
char SendBuf[BUFFER_SIZE];
//操作类型表示
bool OperType;
}PER_IO_OPERATION_DATA,*PPER_IO_OPERATION_DATA;
typedef map<SOCKET,TClient*> TSortClients; //排序的客户端
typedef map<ULONG,TPack *> TPacks; //有些数据包需要重组才能合成大数据包回调ProcessRecvData函数,占时保存结构
typedef vector<SOCKET> SOCKETS;
//回调处理数据函数原型
typedef void __stdcall ProcessRecvData(char * pData,ULONG DataLength);
typedef void __stdcall ProcessPeerClose();
typedef void __stdcall ProcessFileTransfer(char *filename,double speed);
DWORD WINAPI ServerWorkerProc(LPVOID lParam); //工作线程
DWORD WINAPI ListenProc(LPVOID lParam);
ULONG ULSize=sizeof(ULONG);
ULONG cSize=sizeof(char);
class TData
{
public:
char *data;
ULONG totalLen;
char *Cur;
void AddType(char type);
void AddInt(ULONG len);
void AddData(char *buf,ULONG len);
char GetType();
ULONG GetInt();
char* GetData(ULONG &retlen);
};
struct TPack
{
char *data;
char *CurPack;
ULONG totalLen;
void clear()
{
CurPack=data;
totalLen=0;
}
void AddData(char*d,ULONG len)
{
memcpy(CurPack,d,len);
CurPack+=len;
totalLen+=len;
}
};
struct TDataMod //用于传输的模型,用malloc和free,大小不超过BUFFER_SIZE
{
char type; //0单独数据包,1连续消息数据包头,2文件数据包头,3连续包的消息体,4文件包的消息体,5是否需要销毁本指针
ULONG Len;
ULONG Channel;
char data;
//1、连续消息第一个包的 Len是长度,Channel是Send的传输号,以后Len就是Send的传输号
//2、文件消息第一个包的 Len是长度,Channel是Send的传输号,以后Len就是Send的传输号
//3、单独包是只有Len长度,Index是数据内容
};
struct TFileDataHead
{
char type;
ULONG Channel;
TCHAR szFileTitle[128]; //文件的标题名
DWORD dwFileAttributes; //文件的属性
FILETIME ftCreationTime; //文件的创建时间
FILETIME ftLastAccessTime; //文件的最后访问时间
FILETIME ftLastWriteTime; //文件的最后修改时间
DWORD nFileSizeHigh; //文件大小的高位双字
DWORD nFileSizeLow; //文件大小的低位双字
DWORD dwReserved0; //保留,为0
DWORD dwReserved1; //保留,为0
TCHAR cAlternateFileName;
TCHAR cFileName;
};
//消息包的类型:
//1、单独数据包(TData),type==0,Len为长度,data开始存储的是数据 (MinDataLen)
//2、连续消息数据包头,type==1,Len为消息体总长度,Channel是当前通道号,data信息数据(MinDataHeadLen)
//3、连续消息中间数据包,type==3,Len为Channel号,data信息数据(MinDataLen)
//4、文件头TFileDataHead,type==2
//5、文件中间数据包,type==4,Len为Channel号,data信息数据(MinDataLen)
ULONG MinDataLen=ULSize+cSize;
ULONG MinDataHeadLen=MinDataLen+ULSize;
ULONG MinFileHeadLen=sizeof(TFileDataHead);
class TClient //用于中间实现的类,不能直接使用
{
public:
TClient();
~TClient();
void OnReceive(char *data,ULONG len);//data是一个全局指针
private:
void clear();
ProcessPeerClose *m_pfPeerClose;
//客户端消息回调函数
ProcessRecvData *m_pfRecvData;
//本端管理者指针
TClients *m_ClientManager;
//临时存放分块数据包进行组装
TPacks m_Receivepacks;
//本端的SOCKET号
SOCKET m_Sock;
//对端的IP
char m_RemoteIP[16];
//对端的端口
ULONG m_RemotePort;
//临时存放不足一帧的数据
TPack m_tempDta;
friend DWORD WINAPI ServerWorkerProc(LPVOID lParam);
friend class TClients;
};
class TClients //外部接口类,可以用其公有方法接口
{
public:
TClients(LPCTSTR strLogPath="TClientsLog.log");
~TClients();
SOCKET CreateClient(const char *pSerIp,ULONG iSvrPort=SVRPORT,
ProcessRecvData* OnProcessRecvData=NULL,ProcessPeerClose* OnProcessPeerClose=NULL);
bool Disconnet(SOCKET sClient);
bool DisconnetAll();
bool SendMsg(SOCKET sClient,char * pData,ULONG Length);
bool SendFile(SOCKET sClient,const char * filename,ProcessFileTransfer *OnFileTrans=NULL){return true;}
bool GetRemoteAddress(SOCKET sClient,char * IP,ULONG &port);
bool GetLocalIP(char *&IP);
private:
//完成句柄
HANDLE CompletionPort;
//客户信息临界保护量
CRITICAL_SECTION cClientSection;
//当前发送的通道号
ULONG Channel;
//客户信息列表
TSortClients m_clients;
//写日志文件
char m_LogPath[MAX_PATH];
void WriteLogString(const char *format,...);
void InitNetWork();
void UnInit();
private:
friend class TClient;
friend DWORD WINAPI ServerWorkerProc(LPVOID lParam);
};
#endif // !defined(AFX_TSOCKET_H__46FFF420_23C3_4356_A88D_AEBDA61EA186__INCLUDED_)
//***********************************************************************************
//文件说明:TSocket.cpp
//功能: 文件传输客户端实现头文件
//使用说明:使用TCP的IOCP实现,可以传送大消息包、文件,线程安全同一客户端可以同时发送消息、文件
// 1、用TClients创建一个对象,pClients
// 2、调用pClients->CreateClient(...)函数,参数1、2是要连接的服务端IP和端口,
// 3服务端返回消息的事件回调处理函数,4是服务端断开连接的事件回调处理函数
// 3、调用pClients->SendMsg(...)给对端发消息
// 4、调用pClients->SendFile(...)给对端发文件
// 5、调用pClients->Disconnet(...)主动断开连接
// 6、销毁pClients对象
//时间: 2010.5.1 23:13:56
//作者: 废人
//***********************************************************************************
#include "stdafx.h"
#include "TSocket.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#pragma warning(disable:4800)
DWORD WINAPI ServerWorkerProc(LPVOID lParam)
{
TClients* clientManager=(TClients*)lParam;
HANDLE CompletionPort=clientManager->CompletionPort;
DWORD ByteTransferred;
LPPER_HANDLE_DATA PerHandleData;
PPER_IO_OPERATION_DATA PerIoData;
DWORD RecvByte;
while(true)
{
bool bSuccess=GetQueuedCompletionStatus(CompletionPort,
&ByteTransferred,
(LPDWORD)&PerHandleData,
(LPOVERLAPPED* )&PerIoData,
INFINITE);
//退出信号到达,退出线程
if(ByteTransferred==-1 && PerIoData==NULL)
{
return 1L;
}
//客户机已经断开连接或者连接出现错误
if(ByteTransferred==0 && (PerIoData->OperType==RECV_POSTED || PerIoData->OperType==SEND_POSTED))
{
//将该客户端数据删除
::EnterCriticalSection(&clientManager->cClientSection);
clientManager->m_clients.erase(PerHandleData->client->m_Sock);
::LeaveCriticalSection(&clientManager->cClientSection);
//记录退出日志
clientManager->WriteLogString("Ip: %s,port:%d,Socket : %d Disconneted",PerHandleData->client->m_RemoteIP,
PerHandleData->client->m_RemotePort,PerHandleData->client->m_Sock);
TRACE("
Socket : %d Disconneted",PerHandleData->client->m_Sock);
//调用回调函数,通知上层该客户端已经断开
PerHandleData->client->OnReceive(NULL,0);
//关闭套接口
closesocket(PerHandleData->client->m_Sock);
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}
//为读操作完成,处理数据
if(PerIoData->OperType==RECV_POSTED)
{
//调用回调函数,处理数据
PerHandleData->client->OnReceive(PerIoData->RecvBuf,ByteTransferred);
//将源数据置空
memset(PerIoData->RecvBuf,0,BUFFER_SIZE);
ByteTransferred=0;
//重置IO操作数据
unsigned long Flag=0;
ZeroMemory(&(PerIoData->OverLapped),sizeof(OVERLAPPED));
PerIoData->RecvDataBuf.buf=PerIoData->RecvBuf;
PerIoData->RecvDataBuf.len=BUFFER_SIZE;
PerIoData->OperType=RECV_POSTED;
//提交另一个Recv请求
WSARecv(PerHandleData->client->m_Sock,&(PerIoData->RecvDataBuf),1,&RecvByte,&Flag,&(PerIoData->OverLapped),NULL);
}
//发送完成,置空缓冲区,释放缓冲区
if(PerIoData->OperType==SEND_POSTED)
{
memset(PerIoData,0,sizeof(PER_IO_OPERATION_DATA));
GlobalFree(PerIoData);
ByteTransferred=0;
}
}
return 0L;
}
TClients::TClients(LPCTSTR strLogPath)
{
if (NULL==strLogPath||strlen(strLogPath)>=MAX_PATH)
{
strcpy(m_LogPath,"TClientsLog.log");
}else
{
strcpy(m_LogPath,strLogPath);
}
InitNetWork();
}
TClients::~TClients()
{
UnInit();
}
void TClients::UnInit()
{
//1、关闭所有连接
DisconnetAll();
//2、退出工作线程
SYSTEM_INFO sys_Info;
GetSystemInfo(&sys_Info);
for(int i=0;i<sys_Info.dwNumberOfProcessors*2+2;i++)
{
//寄出退出消息
PostQueuedCompletionStatus(CompletionPort,-1,-1,NULL);
}
//3、删除所有的对象
for (TSortClients::iterator it=m_clients.begin();it!=m_clients.end();it++)
{
delete it->second;
}
DeleteCriticalSection(&cClientSection);
}
void TClients::InitNetWork()
{
WSADATA wsaData;
//1、Net Start Up
WSAStartup(MAKEWORD(0x02,0x02),&wsaData);
if(WSAStartup(MAKEWORD(0x02,0x02),&wsaData)!=0)WriteLogString("WSAStartUp Faild With Error: %d",WSAGetLastError());
//2、创建完成端口
CompletionPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
if(CompletionPort==INVALID_HANDLE_VALUE)
{
WriteLogString("CreateIoCompletionPort faild with Error: %d",GetLastError());
return;
}
//3、创建工作线程池
SYSTEM_INFO sys_Info;
GetSystemInfo(&sys_Info);
for(int i=0;i<sys_Info.dwNumberOfProcessors*2+2;i++)
{
HANDLE ThreadHandle;
DWORD ThreadID;
ThreadHandle=CreateThread(NULL,0,ServerWorkerProc,this,0,&ThreadID);
if(ThreadHandle==NULL)
{
WriteLogString("Create Server Work Thread faild with Error: %d",WSAGetLastError());
return ;
}
CloseHandle(ThreadHandle);
}
InitializeCriticalSection(&cClientSection);
}
bool TClients::GetRemoteAddress(SOCKET sClient,char * IP,ULONG &port)
{
TClient *client=NULL;
EnterCriticalSection(&cClientSection);
TSortClients::iterator it=m_clients.find(sClient);
if (it!=m_clients.end())
{
client=it->second;
}
LeaveCriticalSection(&cClientSection);
if (!client)return false;
strcpy(IP,client->m_RemoteIP);
port=client->m_RemotePort;
return true;
}
bool TClients::GetLocalIP(char *&IP)
{
char Name[100];
hostent *pHostEntry;
in_addr rAddr;
if( 0 == gethostname ( Name, 100 ) )
{
pHostEntry = gethostbyname( Name );
if( pHostEntry != NULL )
{
memcpy( &rAddr, pHostEntry->h_addr_list[0], sizeof(struct in_addr) );
sprintf(IP,"%s",inet_ntoa( rAddr ));
return true;
}
else
{
WriteLogString("GetHostIp faild with Error: %d",WSAGetLastError());
}
}
return false;
}
SOCKET TClients::CreateClient(const char *pSerIp,ULONG iSvrPort,
ProcessRecvData* OnProcessRecvData,ProcessPeerClose* OnProcessPeerClose)
{
int Error=0;
//Socket Create
SOCKET sock;
if((sock=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)
{
Error = WSAGetLastError();
WriteLogString("WSASocket Faild With Error: %d",Error);
return INVALID_SOCKET;
}
struct sockaddr_in inAddr;
inAddr.sin_family=AF_INET;
inAddr.sin_port=htons(iSvrPort);
inAddr.sin_addr.S_un.S_addr=inet_addr(pSerIp);
if (connect(sock,(PSOCKADDR)&inAddr,sizeof(inAddr))==SOCKET_ERROR )
{
Error=WSAGetLastError();
WriteLogString("connect Server Socket Faild :%d",Error);
return INVALID_SOCKET;
}
TClient *client=new TClient;
client->m_ClientManager=this;
client->m_pfPeerClose=OnProcessPeerClose;
client->m_pfRecvData=OnProcessRecvData;
strcpy(client->m_RemoteIP,pSerIp);
client->m_RemotePort=iSvrPort;
client->m_Sock=sock;
//申请新的句柄操作数据
LPPER_HANDLE_DATA PerHandleData=(LPPER_HANDLE_DATA) GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));
//句柄数据
PerHandleData->client=client;
//存储客户信息
::EnterCriticalSection(&cClientSection);
m_clients[sock]=client;
::LeaveCriticalSection(&cClientSection);
//转储信息
WriteLogString("Ip: %s,port:%d,Socket : %d Conneted",client->m_RemoteIP,client->m_RemotePort,client->m_Sock);
//关联客户端口到完成端口,句柄数据在此时被绑定到完成端口
CreateIoCompletionPort((HANDLE)sock,CompletionPort,(DWORD)PerHandleData,0);
//Io操作数据标志
PPER_IO_OPERATION_DATA PerIoData=(PPER_IO_OPERATION_DATA) GlobalAlloc(GPTR,sizeof(PER_IO_OPERATION_DATA));
unsigned long Flag=0;
DWORD RecvByte;
ZeroMemory(&(PerIoData->OverLapped),sizeof(OVERLAPPED));
PerIoData->RecvDataBuf.buf=PerIoData->RecvBuf;
PerIoData->RecvDataBuf.len=BUFFER_SIZE;
PerIoData->OperType=RECV_POSTED;
//提交首个接收数据请求
//这时
//如果客户端断开连接
//则也可以以接收数据时得到通知
WSARecv(sock,&(PerIoData->RecvDataBuf),1,&RecvByte,&Flag,&(PerIoData->OverLapped),NULL);
return sock;
}
void TClients::WriteLogString(const char *format,...)
{
char buf[1025]={0};
try
{
SYSTEMTIME sysTm;
::GetLocalTime(&sysTm);
sprintf(buf,"%d-%d-%d %d:%d:%d:%3d %s
",sysTm.wYear,sysTm.wMonth,sysTm.wDay,sysTm.wHour,
sysTm.wMinute,sysTm.wSecond,sysTm.wMilliseconds,buf);
int len=strlen(buf);
va_list arg;
va_start(arg,format);
_vsntprintf(buf+len,1024-len, format,arg);
va_end(arg);
FILE *fp=fopen(m_LogPath,"a");
if (!fp)return;
fwrite(buf,strlen(buf),1,fp);
fclose(fp);
}
catch (...)
{
}
}
bool TClients::Disconnet(SOCKET sClient)
{
TClient *client=NULL;
::EnterCriticalSection(&cClientSection);
TSortClients::iterator it=m_clients.find(sClient);
if (it!=m_clients.end())
{
client=it->second;
m_clients.erase(sClient);
}
::LeaveCriticalSection(&cClientSection);
if (client)
{
delete client;
shutdown(sClient,1);
return closesocket(sClient)==SOCKET_ERROR?false:true;
}
return false;
}
bool TClients::DisconnetAll()
{
::EnterCriticalSection(&cClientSection);
for (TSortClients::iterator it=m_clients.begin();it!=m_clients.end();it++)
{
shutdown(it->first,1);
closesocket(it->first);
delete it->second;
}
m_clients.clear();
::LeaveCriticalSection(&cClientSection);
return true;
}
bool TClients::SendMsg(SOCKET sClient,char * pData,ULONG Length)
{
if (sClient==INVALID_SOCKET||pData==NULL||Length==0)return false;
int head=0;
ULONG packlen=BUFFER_SIZE-MinDataLen;
if (Length>packlen)//需要分包
{
head=1;
}
//申请操作键
PPER_IO_OPERATION_DATA PerIoData;
ULONG left=Length;
TData dat;
while (left>0)
{
PerIoData=(PPER_IO_OPERATION_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_OPERATION_DATA));
//准备缓冲
unsigned long Flag=0;
DWORD SendByte;
ZeroMemory(&(PerIoData->OverLapped),sizeof(OVERLAPPED));
dat.data=PerIoData->SendBuf;
if (0==head)
{
dat.AddType(0);
dat.AddInt(Length);
dat.AddData(pData,Length);
left=0;
}else if(1==head)
{
dat.AddType(1);
dat.AddInt(Length);
if (0==++Channel)Channel=1;
dat.AddInt(Channel);
dat.AddData(pData,BUFFER_SIZE-MinFileHeadLen);
pData+=BUFFER_SIZE-MinFileHeadLen;
head=2;
left=Length-packlen;
}else
{
dat.AddType(3);
dat.AddInt(Channel);
if (left>packlen)
{
dat.AddData(pData,packlen);
left-=packlen;
}else
{
dat.AddData(pData,left);
left=0;
}
}
PerIoData->SendDataBuf.buf=dat.data;
PerIoData->SendDataBuf.len=dat.totalLen;
PerIoData->OperType=SEND_POSTED;
int bRet=WSASend(sClient,&(PerIoData->SendDataBuf),1,&SendByte,Flag,&(PerIoData->OverLapped),NULL);
if(bRet==SOCKET_ERROR && GetLastError()!=WSA_IO_PENDING)
{
WriteLogString("WSASend With Error : %d",GetLastError());
return false;
}
}
return true;
}
/************************************************************************************************************/
/************************************************************************************************************/
TClient::TClient()
{
m_tempDta.data=new char[2*BUFFER_SIZE];
m_tempDta.CurPack=m_tempDta.data;
m_tempDta.totalLen=0;
}
TClient::~TClient()
{
clear();
delete[] m_tempDta.data;
}
void TClient::clear()
{
for (TPacks::iterator it=m_Receivepacks.begin();it!=m_Receivepacks.end();it++)
{
delete[] it->second->data;
delete it->second;
}
}
void TClient::OnReceive(char *data,ULONG len)//data是一个全局指针
{
//1、已经断开连接
if (0==len&&m_pfPeerClose)
{
m_pfPeerClose();
clear();
return;
}
//2、先处理以前遗留的数据,有数据就合起来
lb1: if(m_tempDta.totalLen==0)//上面没有遗留数据,不用拷贝直接使用data指针
{
if (len<=MinDataLen)//两个数据包相加都不满足最小需求,继续等待
{
m_tempDta.AddData(data,len);
return;
}
TData dat;
dat.data=data;
dat.totalLen=len;
char type=dat.GetType();
ULONG ilen=dat.GetInt();
switch(type)
{
case 1:
{
ULONG Channel=dat.GetInt();
if (0==Channel||len!=BUFFER_SIZE)//不足一帧,交由m_tempDta去等待
{
m_tempDta.AddData(data,len);
return;
}
TPack *pack=new TPack;
pack->data=new char[ilen];
pack->CurPack=pack->data;
pack->totalLen=ilen;
pack->AddData(data+MinDataHeadLen,len-MinDataHeadLen);
m_Receivepacks[Channel]=pack;
break;
}
case 2:
{
break;
}
case 3:
{
TPack *pack=m_Receivepacks[ilen];
ULONG curlen=pack->CurPack-pack->data;
if (pack->totalLen==len-MinDataLen+curlen)//已经完成了数据包的接收
{
pack->AddData(data+MinDataHeadLen,len-MinDataHeadLen);
m_pfRecvData(pack->data,pack->totalLen);
delete[] pack->data;
delete pack;
m_Receivepacks.erase(ilen);
}else if (pack->totalLen>len-MinDataLen+curlen)
{
if (len!=BUFFER_SIZE)//不满一帧,交由m_tempDta继续等待
{
m_tempDta.AddData(data,len);
}else //满一帧,直接加入缓存
{
pack->AddData(data+MinDataHeadLen,len-MinDataHeadLen);
}
}else //已经满一帧,并附带了多余的其他帧
{
pack->AddData(data+MinDataHeadLen,pack->totalLen-curlen);
m_pfRecvData(pack->data,pack->totalLen);
ULONG tlen=MinDataHeadLen+pack->totalLen-curlen;
data+=tlen;
len-=tlen;
delete[] pack->data;
delete pack;
m_Receivepacks.erase(ilen);
goto lb1;//重新计算
}
break;
}
case 4:
{
break;
}
default:
{
ULONG tlen=MinDataLen+ilen;
if (tlen==len)
{
m_pfRecvData(dat.Cur,ilen);
}else if (tlen>len)
{
m_tempDta.AddData(data,len);
}else
{
m_pfRecvData(dat.Cur,ilen);
data+=tlen;
len-=tlen;
goto lb1;//重新计算
}
break;
}
}
}else //上面有遗留数据,
{
m_tempDta.AddData(data,len);
lb2: if (m_tempDta.totalLen<=MinDataLen)return;//两个数据包相加都不满足最小需求,继续等待
TData dat;
dat.data=m_tempDta.data;
dat.totalLen=m_tempDta.totalLen;
char type=dat.GetType();
ULONG ilen=dat.GetInt();
switch(type)
{
case 1:
{
ULONG Channel=dat.GetInt();
if (0==Channel||m_tempDta.totalLen<BUFFER_SIZE)//一帧都不够,继续等待
{
return;
}
TPack *pack=new TPack;
pack->data=new char[ilen];
pack->CurPack=pack->data;
pack->totalLen=ilen;
pack->AddData(m_tempDta.data+MinDataHeadLen,BUFFER_SIZE-MinDataHeadLen);
m_Receivepacks[Channel]=pack;
if (m_tempDta.totalLen==BUFFER_SIZE)
{
m_tempDta.clear();
}else
{
memcpy(m_tempDta.data,m_tempDta.data+BUFFER_SIZE,m_tempDta.totalLen-BUFFER_SIZE);
m_tempDta.totalLen-=BUFFER_SIZE;
goto lb2;//重新计算
}
break;
}
case 2:
{
break;
}
case 3:
{
TPack *pack=m_Receivepacks[ilen];
ULONG curlen=pack->CurPack-pack->data;
if (pack->totalLen==dat.totalLen-MinDataLen+curlen)//已经完成了数据包的接收
{
pack->AddData(dat.data+MinDataHeadLen,dat.totalLen-MinDataHeadLen);
m_pfRecvData(pack->data,pack->totalLen);
delete[] pack->data;
delete pack;
m_Receivepacks.erase(ilen);
}else if (pack->totalLen>len-MinDataLen+curlen)
{
if (dat.totalLen==BUFFER_SIZE)//不满一帧,继续等待
{
pack->AddData(dat.data+MinDataHeadLen,len-MinDataHeadLen);
m_tempDta.AddData(dat.data,dat.totalLen);
}else if(dat.totalLen>BUFFER_SIZE) //满一帧,直接加入缓存
{
pack->AddData(dat.data+MinDataHeadLen,BUFFER_SIZE-MinDataHeadLen);
memcpy(m_tempDta.data,dat.data+BUFFER_SIZE,dat.totalLen-BUFFER_SIZE);
m_tempDta.totalLen-=BUFFER_SIZE;
goto lb2;
}
}else
{
pack->AddData(dat.data+MinDataHeadLen,pack->totalLen-curlen);
m_pfRecvData(pack->data,pack->totalLen);
ULONG tlen=MinDataHeadLen+pack->totalLen-curlen;
memcpy(m_tempDta.data,dat.data+tlen,dat.totalLen-tlen);
data+=tlen;
m_tempDta.totalLen-=tlen;
delete[] pack->data;
delete pack;
m_Receivepacks.erase(ilen);
goto lb2;//重新计算
}
break;
}
case 4:
{
break;
}
default:
{
ULONG tlen=MinDataLen+ilen;
if (tlen==m_tempDta.totalLen)
{
m_pfRecvData(dat.Cur,ilen);
m_tempDta.clear();
}else if (tlen<m_tempDta.totalLen)
{
m_pfRecvData(dat.Cur,ilen);
memcpy(m_tempDta.data,dat.Cur+ilen,m_tempDta.totalLen-tlen);
m_tempDta.totalLen-=tlen;
goto lb2;//重新计算
}
break;
}
}
}
}
void TData::AddType(char type)
{
totalLen=cSize;
memcpy(data,&type,totalLen);
}
void TData::AddInt(ULONG len)
{
memcpy(data+totalLen,&len,ULSize);
totalLen+=ULSize;
}
void TData::AddData(char *buf,ULONG len)
{
int clen=len+totalLen>BUFFER_SIZE?BUFFER_SIZE-len:len;
memcpy(data+totalLen,buf,clen);
totalLen+=clen;
}
char TData::GetType()
{
char type;
memcpy(&type,data,cSize);
Cur=data+cSize;
return type;
}
ULONG TData::GetInt()
{
if (Cur-data+ULSize>totalLen)return 0;
ULONG l;
memcpy(&l,Cur,ULSize);
Cur+=ULSize;
return l;
}
char* TData::GetData(ULONG &retlen)
{
retlen=totalLen-(ULONG)(Cur-data);
return Cur;
}