看流星社区

 找回密码
 注册账号
查看: 2946|回复: 0

IOCP SOCKET类(改进版)

[复制链接]

该用户从未签到

发表于 2015-4-16 15:42:31 | 显示全部楼层 |阅读模式
//***********************************************************************************
//文件说明: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;
}
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-4-18 10:16

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表