//*********************************************************************************** //文件说明: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("\nSocket : %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\t%s\n",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; }