1. 程式人生 > >一個封裝好的使用完成埠的socket通訊類

一個封裝好的使用完成埠的socket通訊類

//***********************************************************************************
//檔案說明: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;
}