一个封装好的使用完成端口的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;
}








你可能感兴趣的:(一个封装好的使用完成端口的socket通讯类)