zoukankan      html  css  js  c++  java
  • 一个封装好的使用完成端口的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("
    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;
    }
    
    
    
    
    


    
    


  • 相关阅读:
    开学考试学生成绩管理Java
    动手动脑问题1
    数据库的链接错误分析
    ASP.NET自定义错误页面
    php declare
    HTTP运行期与页面执行模型
    分部类(Partial Classes)
    ASP.NET:小编浅谈泛型的使用
    Windows 2003 SP2下安装IIS无法复制文件
    php 的include require 区别
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318555.html
Copyright © 2011-2022 走看看