Error

C++博客 首页 新随笔 联系 聚合 管理
  217 Posts :: 61 Stories :: 32 Comments :: 0 Trackbacks

简化后的CNetClient类图:

image

 

本次是分享下整体设计思想,不研究细节网络实现。

    CNetClient用户客户端的网络处理。主要功能需求如下:

*能接收远端数据

*能把接收到的数据送到上层处理

*能向远端发送数据

**发送和接收都是异步

**CNetClient本身是一个底层服务,对上层是异步的

 

针对上述需求GodofMoney实现的非常简单:

针对发送和接收单独开线程,回调OnRecvProc OnSend

和上层数据交互通过两个队列完成,一个发送队列,一个接收队列。

上层将需要发送的数据放到发送队列,底层将接收到的数据调用上层给的处理函数处理后push出去

 

先这么多吧,以后还会继续分析,,,

////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////NetClient.h///////////////////////

//! NetClient.h: interface for the CNetClient class.
//!发送接收原始网络包执行类

#if !defined(AFX_NETCLIENT_H__CF62B9AC_911A_4CE6_81B2_55CB2588A42E__INCLUDED_)
#define AFX_NETCLIENT_H__CF62B9AC_911A_4CE6_81B2_55CB2588A42E__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif //! _MSC_VER > 1000

#define SERVERPORT 10012
#define BUFFER_SIZE 4096

#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#pragma once
/*******************************************************************************************
*******************************************************************************************/
//!错误定义:套接字上的数据操作正忙
#define  CLIENT_FUNERROR 0x100
//!TCP winsock连接类
class CClientSocket 
{
    friend class CNetClient;
public:
    CClientSocket();
    CClientSocket(bool & bSuccess,int iSockType,char * szSvrAddr,unsigned short iSvrPort)
    {
        bSuccess=false;
        bSuccess=CreateSocket(iSockType);
        bSuccess=ConnectSocket(szSvrAddr,iSvrPort);
    }
    virtual ~CClientSocket();
public:
    //!释放资源
    void UnInit();
    //!winsocket处理
    bool CreateSocket(int iSockType){
        return CreateSocket(&m_Socket,iSockType);
    }
    bool BindSocket(char *szHostAddr,unsigned short  iHostPort){
        return BindSocket(m_Socket,szHostAddr,iHostPort);
    }
    bool ShutDownSocket(){
        return ShutDownSocket(m_Socket);
    }
    bool CloseSocekt(){
        return CloseSocket(m_Socket);
    }
    bool ConnectSocket(char * szDestAddr,unsigned short iDestPort);
    //!发送与接收数据
    /*
     *char * data        数据指针
     *DWORD len            数据长度
     *DWORD *retlen        处理长度
     *DWORD time        等待时间
     *返回:true为成功,否则为失败
     */
    bool SendMsg(char * data,DWORD len,DWORD *retlen,DWORD time);
    bool RecvMsg(char * data,DWORD len,DWORD *retlen,DWORD time);

    char        m_szDestAddr[255];   
    BOOL        m_bEnData;
protected:
    bool CreateSocket(SOCKET *pNewSocket,int iSockType);
    bool BindSocket(SOCKET BindSocket,char *szHostAddr,unsigned short iHostPort);
    bool ShutDownSocket(SOCKET nowSocket);
    bool CloseSocket(SOCKET nowSocket);
    bool SendDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time);
    bool RecvDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time);
private:
    bool SendData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time);
    bool RecvData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time);
private:
    SOCKET m_Socket;
    WSAEVENT m_hExitEvent;
    struct sockaddr_in inAddr;
};
/*******************************************************************************
消息队列类:用于存储消息队列,即待发送的消息的集合,或者是接收过待处理的集合
*******************************************************************************/
template <class T> class Queue;
//!链式队列结点定义
template <class T> class QueueNode
{
    friend class Queue<T>;
private:
    T data;//!数据域
    QueueNode<T> *link;//!链域
    QueueNode(T d,QueueNode *l=NULL):link(l){memcpy(&data,&d,sizeof(T));}//!构造函数
};
//!链式队列类定义
template <class T> class Queue
{
public:
    Queue():rear(NULL),front(NULL),count(0){}//!构造函数
    ~Queue();//!析构函数
    void EnQueue(const T & item);//!将item加入到队列中
    T DeQueue();//!删除并返回队头元素
    T GetFront(){return front->data;}//!查看队头元素的值
    void MakeEmpty();//!置空队列
    int IsEmpty() const {return front==NULL;}//!判断队列空否
    int GetSize() const {return count;}
private:
    QueueNode<T> *front ,*rear;//!队头,队尾指针
    int            count;
};
typedef struct _MSG_NODE
{
    unsigned long DataLength;
    char pData[BUFFER_SIZE];
}MSG_NODE,*PMSG_NODE;
/*********************************************************************************/

//!通过回调函数调用上层处理函数
typedef void __stdcall ProcessRecvClientData(char * pData,unsigned long DataLength, void *pContext);

//!内部采用标准三线程模型
DWORD _stdcall SendProc(LPVOID pParam);
DWORD _stdcall WorkProc(LPVOID pParam);
DWORD _stdcall RecvProc(LPVOID pParam);
//!网络客户端类
class CNetClient 
{
public:
    CNetClient();
    virtual ~CNetClient();
public:
    //!初试化
    /*
     *ProcessRecvClientData* pProcessRecvClientData        接收数据回调函数
     *void *pProcessRecvContext                接收数据回调函数上下文
     *LPCTSTR szSvrAddr                        连接地址
     *unsigned long iSvrPort=SERVERPORT        连接端口
     */
    bool Init(ProcessRecvClientData* pProcessRecvClientData,
        void *pProcessRecvContext,
        LPCTSTR szSvrAddr,
        unsigned long iSvrPort=SERVERPORT,
        BOOL    bEnData = TRUE);
    //!清除跟释放资源
    void UnInit(BOOL bWait = FALSE);
    //!发送数据
    bool SendMsg(char * pData,unsigned long DataLength);
    //!返回本地地址
    LPCTSTR GetLocalIP(){return IsStart ? HostIpAddr:NULL;}
    bool IsStarted(){return IsStart;}
protected:
    int InitNetWork(LPCTSTR szSvrAddr,
        unsigned int SvrPort=SERVERPORT,
        LPCTSTR HostIpAddr=NULL);
    void WriteLogString(LPCTSTR strLog);

    CClientSocket m_sClient;
    ProcessRecvClientData* m_pProcessRecvClientData;
    void*             m_pProcessRecvContext;
    Queue <MSG_NODE> SendMsgQueue;
    CRITICAL_SECTION SendMsgQueSection;
    HANDLE hSendEvent;
    Queue <MSG_NODE> RecvMsgQueue;
    CRITICAL_SECTION RecvMsgQueSection;
    //!开始工作事件
    HANDLE hWorkEvent;
    //!退出事件   
    HANDLE hExitEvent;
    //!是否用户进行了反初始化操作,如果是:接收线程将不再调用回调函数
    bool bOprUnInit;
    //!是否已经被驱动
    bool IsStart;
    TCHAR HostIpAddr[16];

    BOOL m_bEnData;

    //!线程资源
    HANDLE RecvHan;
    HANDLE WorkHan;
    HANDLE ThreHan;
    static DWORD WINAPI SendProc(LPVOID pParam);
    static DWORD WINAPI WorkProc(LPVOID pParam);
    static DWORD WINAPI RecvProc(LPVOID pParam);
    void  OnSendProc();
    void  OnWorkProc();
    void  OnRecvProc();
};
#endif //! !defined(AFX_NETCLIENT_H__CF62B9AC_911A_4CE6_81B2_55CB2588A42E__INCLUDED_)

/////////////////////////////////////////////////////////////////////////////////////////////////////

/////CNetClient.cpp//////////////////////////

// NetClient.cpp: implementation of the CNetClient class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <atlbase.h>
#include "NetClient.h"
#include "EnDeData.h"
#include <fstream>
using namespace std;
#define  W2A

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CNetClient::CNetClient()
{
    IsStart=false;
    bOprUnInit=false;
    m_pProcessRecvClientData=NULL;
    m_pProcessRecvContext = NULL;
    WorkHan = NULL;
    RecvHan = NULL;
    ThreHan = NULL;
    hSendEvent=CreateEvent(NULL,false,false,NULL);
    hWorkEvent=CreateEvent(NULL,false,false,NULL);
    hExitEvent=CreateEvent(NULL,false,false,NULL);
}
CNetClient::~CNetClient()
{
    CloseHandle(hSendEvent);
    CloseHandle(hWorkEvent);
    CloseHandle(hExitEvent);
}
DWORD  CNetClient::SendProc(LPVOID pParam)
{
    reinterpret_cast<CNetClient*>(pParam)->OnSendProc();
    return 0;
}
void CNetClient::OnSendProc()
{
    CNetClient * pNetClient=(CNetClient*) this;
    HANDLE event[2];
    event[0]=pNetClient->hSendEvent;
    event[1]=pNetClient->hExitEvent;

    while(true)
    {
        Sleep(10);
        ::EnterCriticalSection(&pNetClient->SendMsgQueSection);
        //队列为空,等待发送事件触发
        if(pNetClient->SendMsgQueue.IsEmpty())
        {
            ::LeaveCriticalSection(&pNetClient->SendMsgQueSection);
            //为空,或者发送完毕
            ResetEvent(pNetClient->hSendEvent);
            //TRACE("\nTheSendProc Is Waiting....");   
            DWORD Index=::WaitForMultipleObjects(2,event,false, 50);
            if((Index-WAIT_OBJECT_0) == WAIT_TIMEOUT)
            {
                if(pNetClient->bOprUnInit)
                {
                    return ;//应用程序请求退出   
                }
            }
            else if((Index-WAIT_OBJECT_0)==1)
            {
                return ;
            }
        }
        else
        {
            //取下一个结点,并发送
            MSG_NODE p=pNetClient->SendMsgQueue.DeQueue();
            //释放队列
            ::LeaveCriticalSection(&pNetClient->SendMsgQueSection);
            DWORD retlen;
            bool bRet=pNetClient->m_sClient.SendMsg(p.pData,p.DataLength,&retlen,WSA_INFINITE);
            if(bRet==false || retlen!=p.DataLength)
            {
                if(GetLastError()!=CLIENT_FUNERROR)
                pNetClient->m_pProcessRecvClientData(NULL,0, pNetClient->m_pProcessRecvContext);
                //pNetClient->UnInit();
            }   
        }
    }
    return ;
}
DWORD  CNetClient::WorkProc(LPVOID pParam)
{
    reinterpret_cast<CNetClient*>(pParam)->OnWorkProc();
    return 0;
}

void CNetClient::OnWorkProc()
{
    CNetClient* pNetClient=(CNetClient*)this;
    HANDLE event[2];
    event[0]=pNetClient->hWorkEvent;
    event[1]=pNetClient->hExitEvent;
    while(true)
    {
        //Sleep(1);
        ::EnterCriticalSection(&pNetClient->RecvMsgQueSection);
        //队列为空,等待发送事件触发
        if(pNetClient->RecvMsgQueue.IsEmpty())
        {
            ::LeaveCriticalSection(&pNetClient->RecvMsgQueSection);
            //为空,或者发送完毕
            ResetEvent(pNetClient->hWorkEvent);
            //TRACE("\nTheWorkProc Is Waiting....");           
            DWORD Index=::WaitForMultipleObjects(2,event,false, 100);
            if((Index-WAIT_OBJECT_0) == WAIT_TIMEOUT)
            {
                if(pNetClient->bOprUnInit)
                {
                    return ;//应用程序请求退出   
                }
            }
            else if((Index-WAIT_OBJECT_0)==1)
            {
                return ;
            }
        }
        else
        {
            //取下一个结点,并发送
            MSG_NODE p=pNetClient->RecvMsgQueue.DeQueue();
            //释放队列
            ::LeaveCriticalSection(&pNetClient->RecvMsgQueSection);
            //调用回调函数,处理数据
            if(m_bEnData)
            {
                char outData[4096];
                long outLen = 4096;
                DeData(p.pData, p.DataLength, outData, outLen);
                pNetClient->m_pProcessRecvClientData(outData,outLen, pNetClient->m_pProcessRecvContext);
            }
            else
            {
                pNetClient->m_pProcessRecvClientData(p.pData,p.DataLength, pNetClient->m_pProcessRecvContext);

            }
        }
    }
    return ;
}
DWORD CNetClient::RecvProc(LPVOID pParam)
{
    try
    {
        reinterpret_cast<CNetClient*>(pParam)->OnRecvProc();
    }
    catch (...) {
    }
    return 0;
}
void CNetClient::OnRecvProc()
{
    char RecvBuf[BUFFER_SIZE];
    DWORD retlen;
    while (true)
    {
        //Sleep(1);
        //TRACE("\nTheRecvThread Is Waiting...");
        if(!m_sClient.RecvMsg(RecvBuf,BUFFER_SIZE,&retlen,WSA_INFINITE) &&  GetLastError()!=CLIENT_FUNERROR)
        {
            if(bOprUnInit)
            {
                return ;//应用程序请求退出   
            }
            //连接已经被断开,通知上层(通过调用回调函数)
            m_pProcessRecvClientData(NULL,0, m_pProcessRecvContext);
            //pNetClient->UnInit();
            return ;
        }
        else
        {
            if(bOprUnInit)
            {
                return ;//应用程序请求退出   
            }
            //没收到字节?还是出错
            if(retlen==0 || retlen > BUFFER_SIZE)
            {
                m_pProcessRecvClientData(NULL,0, m_pProcessRecvContext);
                //pNetClient->UnInit();
                return ;
            }
            //将接收到的数据放到接收队列里
            MSG_NODE Msg;
            Msg.DataLength=retlen;
            memcpy(Msg.pData,RecvBuf,retlen);

            //插入消息队列
            ::EnterCriticalSection(&RecvMsgQueSection);
            if(RecvMsgQueue.IsEmpty())
            {
                RecvMsgQueue.EnQueue(Msg);
                ::LeaveCriticalSection(&RecvMsgQueSection);
                //如果消息队列为空,告诉工作线程可以进行工作了
                SetEvent(hWorkEvent);
            }
            else
            {
                if(RecvMsgQueue.GetSize() > 50)
                {
                    if(!m_bEnData)
                        RecvMsgQueue.MakeEmpty();
                }
                RecvMsgQueue.EnQueue(Msg);

                ::LeaveCriticalSection(&RecvMsgQueSection);
            }
        }
    }
    return ;
}
bool CNetClient::Init(ProcessRecvClientData* pProcessRecvClientData,
                      void *pProcessRecvContext,
                      LPCTSTR szSvrAddr,
                      unsigned long iSvrPort,
                      BOOL    bEnData)
{
    if(pProcessRecvClientData==NULL //回调函数空
        || szSvrAddr==NULL //地址空
        || IsStart)//已经启动过了
    {
        return false;   
    }

    m_bEnData = bEnData;
    m_sClient.m_bEnData = bEnData;

    ::InitializeCriticalSection(&SendMsgQueSection);
    ::InitializeCriticalSection(&RecvMsgQueSection);   
    ResetEvent(hExitEvent);
    IsStart    = false;
    bOprUnInit = false;
    m_pProcessRecvClientData = pProcessRecvClientData;
    m_pProcessRecvContext    = pProcessRecvContext;
    int  bRet=InitNetWork(szSvrAddr,iSvrPort,HostIpAddr);
    if(0==bRet)
    {
        IsStart = true;
        return true;
    }
    else
    {
        m_sClient.UnInit();   
        ::DeleteCriticalSection(&SendMsgQueSection);
        ::DeleteCriticalSection(&RecvMsgQueSection);   
        return false;
    }

}
void CNetClient::UnInit(BOOL bWait)
{
    if(!IsStart)
        return;

    IsStart=false;
    bOprUnInit=true;
    if(hExitEvent)
        SetEvent(hExitEvent);
    if(m_sClient.m_hExitEvent)
        WSASetEvent(m_sClient.m_hExitEvent);

    if(RecvHan)
    {
        /*
        if(bWait)
        {
            bool bloop = true;
            while(bloop)
            {
                if(WaitForSingleObject(RecvHan, 1500) == WAIT_TIMEOUT)
                {
                    if(RecvHan == NULL)
                        bloop =false;
                }
                else
                {
                    bloop =false;
                }
            }
        }
        else
        {
            if(WaitForSingleObject(RecvHan, bWait ? INFINITE : 1500) == WAIT_TIMEOUT)
            {
                TerminateThread(RecvHan, -2);
            }
        }*/
        if(WaitForSingleObject(RecvHan,3000) == WAIT_TIMEOUT)
        {
            TerminateThread(RecvHan, -2);
        }
        CloseHandle(RecvHan);
        RecvHan = NULL;
    }
    if(WorkHan)
    {
        /*
        if(bWait)
        {
            bool bloop = true;
            while(bloop)
            {
                if(WaitForSingleObject(WorkHan, 1500) == WAIT_TIMEOUT)
                {
                    if(WorkHan == NULL)
                        bloop =false;
                }
                else
                {
                    bloop =false;
                }
            }
        }
        else
        {
            if(WaitForSingleObject(WorkHan, bWait ? INFINITE : 1500) == WAIT_TIMEOUT)
                TerminateThread(WorkHan, -2);
        }*/
        if(WaitForSingleObject(WorkHan,3000) == WAIT_TIMEOUT)
        {
            TerminateThread(WorkHan, -2);
        }
        CloseHandle(WorkHan);
        WorkHan = NULL;
    }
    if(ThreHan)
    {
        /*
        if(bWait)
        {
            bool bloop = true;
            while(bloop)
            {
                if(WaitForSingleObject(ThreHan, 1500) == WAIT_TIMEOUT)
                {
                    if(ThreHan == NULL)
                        bloop =false;
                }
                else
                {
                    bloop =false;
                }
            }
        }
        else
        {
            if(WaitForSingleObject(ThreHan, bWait ? INFINITE : 1500) == WAIT_TIMEOUT)
                TerminateThread(ThreHan, -2);
        }*/
        if(WaitForSingleObject(ThreHan,3000) == WAIT_TIMEOUT)
        {
            TerminateThread(ThreHan, -2);
        }
        CloseHandle(ThreHan);
        ThreHan = NULL;
    }
    m_sClient.UnInit();   
    ::DeleteCriticalSection(&SendMsgQueSection);
    ::DeleteCriticalSection(&RecvMsgQueSection);
    SendMsgQueue.MakeEmpty();
    RecvMsgQueue.MakeEmpty();   
    m_pProcessRecvClientData=NULL;
    m_pProcessRecvContext = NULL;
}
int CNetClient::InitNetWork(LPCTSTR szSvrAddr,
                            unsigned int SvrPort,
                            LPCTSTR pHostIpAddress)
{
    int Error=0;
    WSADATA wsaData;
    memset((void *)pHostIpAddress,0,sizeof(pHostIpAddress));
    //Net Start Up
    /*
    char Name[100];
    hostent *pHostEntry;
    in_addr rAddr;
    Error=WSAStartup(MAKEWORD(0x02,0x02),&wsaData);
    if(Error!=0)
    {
        Error = WSAGetLastError();
        //LogStr.Format("WSAStartUp Faild With Error: %d",Error);
        //WriteLogString(LogStr);

        return Error;
    }
    //Make Version
    if ( LOBYTE( wsaData.wVersion ) != 2 ||
         HIBYTE( wsaData.wVersion ) != 2 )
    {
        WSACleanup( );
        //WriteLogString("The Local Net Version Is not 2");

        return -1;
    }*/
    //Get Host Ip
    /*Error = gethostname ( Name, sizeof(Name) );
    if( 0 == Error )
    {
        pHostEntry = gethostbyname( Name );
        if( pHostEntry != NULL )
        {
            memcpy( &rAddr, pHostEntry->h_addr_list[0], sizeof(struct in_addr) );
            sprintf((char * )pHostIpAddress,"%s",inet_ntoa( rAddr ));
        }
        else
        {
            Error = WSAGetLastError();
            //LogStr.Format("GetHostIp faild with Error: %d",Error);
            //WriteLogString(LogStr);

        }
    }
    else
    {
        Error = WSAGetLastError();
        //LogStr.Format("gethostname faild with Error: %d",Error);
        //WriteLogString(LogStr);
    }*/
    //Socket Create
    if(0==Error)
    {
        if(!m_sClient.CreateSocket(SOCK_STREAM))
        {
            Error=WSAGetLastError();
            //LogStr.Format("Create Client Socket Faild :%d",Error);
            ////WriteLogString(LogStr);
            return Error;
        }
    }
    if(0==Error)
    {
        //fix me
        USES_CONVERSION;
        if(!m_sClient.ConnectSocket((char *)W2A(szSvrAddr),SvrPort))
        {
            Error=WSAGetLastError();
            //LogStr.Format("Create Client Socket Faild :%d",Error);
            //WriteLogString(LogStr);
            return -1;
        }
    }
    //启动工作线程,并升高工作线程的等级至最高
    if(0==Error)
    {
        unsigned long WorkID;
        if((WorkHan=CreateThread(NULL,
            0,
            WorkProc,
            this,
            0,
            &WorkID))==NULL)
        {
            Error=GetLastError();
            //LogStr.Format("Create WorkThread Faild With Error %d",Error);
            //WriteLogString(LogStr);
            return Error;
        }
        SetThreadPriority(WorkHan,THREAD_PRIORITY_HIGHEST);
    }
    //启动接收线程
    if(0==Error)
    {
        unsigned long RecvID;
        if((RecvHan=CreateThread(NULL,
            0,
            RecvProc,
            this
            ,
            0,
            &RecvID))==NULL)
        {
            Error=GetLastError();
            //LogStr.Format("Create RecvThread Faild With Error %d",Error);
            //WriteLogString(LogStr);
            SetEvent(hExitEvent);//退出先前创建的线程
            return Error;
        }
    }
    //启动发送线程
    if(0==Error)
    {
        unsigned long ThrID;
        if((ThreHan=CreateThread(NULL,
            0,
            SendProc,
            this,
            0,
            &ThrID))==NULL)
        {
            Error=GetLastError();
            //LogStr.Format("Create SEND Thred Faild With Error %d",Error);
            //WriteLogString(LogStr);
            SetEvent(hExitEvent);//退出先前创建的线程
            return Error;
        }
    }
    return Error;
}
bool CNetClient::SendMsg(char * pData,unsigned long DataLength)
{       
        //未调用初始化函数
        if(!IsStart || pData==NULL || DataLength==0)return false;
        //构造消息
        MSG_NODE Msg;
        Msg.DataLength=DataLength;
        memcpy(Msg.pData,pData,DataLength);
        //插入消息队列
        ::EnterCriticalSection(&SendMsgQueSection);
        if(SendMsgQueue.IsEmpty())
        {
            SendMsgQueue.EnQueue(Msg);
            ::LeaveCriticalSection(&SendMsgQueSection);
            //如果消息队列为空,告诉等待的发送线程可以发送了
            SetEvent(hSendEvent);
        }
        else
        {
            SendMsgQueue.EnQueue(Msg);
            ::LeaveCriticalSection(&SendMsgQueSection);
        }
        return true;
}
void CNetClient::WriteLogString(LPCTSTR strLog)
{
    return;
}
/********************************************************************
函数名  : Queue<T>::~Queue()
输入参数:
输出参数:
功能描述: 队列析构函灵敏,清空所有队列元素
全局变量: 无
调用模块:
附加说明:
********************************************************************/
template <class T>  Queue<T>::~Queue()
{
    QueueNode<T> *p=front;
    while(front!=NULL)
    {
        p=front;
        front=front->link;
        delete p;
    }
}
/********************************************************************
函数名  : Queue<T>::EnQueue
输入参数:
const T & item :要插入的结点的引用
输出参数:
功能描述: 在队列中插入一个结点
全局变量: 无
调用模块:
附加说明:
********************************************************************/
template <class T> void Queue<T>::EnQueue(const T & item)
{
    count ++;
    if(front==NULL)front=rear=new QueueNode<T>(item,NULL);
    else rear=rear->link=new QueueNode<T>(item,NULL);
}
/********************************************************************
函数名  : Queue<T>::DeQueue()
输入参数:
T  :返回被删除结点的值
输出参数:
功能描述: 从队列中取出一个结点,并返回该结点的值
全局变量: 无
调用模块:
附加说明:
********************************************************************/
template <class T> T Queue<T>::DeQueue()
{
    T  retvalue;
    memset(&retvalue,0,sizeof(T));
    if(IsEmpty())
        return retvalue;
    count --;
    QueueNode<T> * p=front;
    retvalue=p->data;
    front=front->link;
    delete p;
    return retvalue;
}
/********************************************************************
函数名  : Queue<T>::MakeEmpty()
输入参数:
输出参数:
功能描述: 将队列元素清空
全局变量: 无
调用模块:
附加说明:
********************************************************************/
template <class T> void Queue<T>::MakeEmpty()
{
    if(front==NULL)return ;
    QueueNode<T> * p=front;
    while(front!=NULL)
    {
        p=front;
        front=front->link;
        delete p;
    }
    front=rear=NULL;
    count = 0;
}
/*************************************************************************/
CClientSocket::CClientSocket()
{
    inAddr.sin_addr.s_addr = INADDR_NONE;
    m_hExitEvent = NULL;
    m_Socket = 0;
    m_szDestAddr[0] = '\0';   
}           
CClientSocket::~CClientSocket()
{
    if(m_hExitEvent != NULL)
        WSACloseEvent(m_hExitEvent);
}
void CClientSocket::UnInit()
{
    if(m_hExitEvent != NULL)
        WSACloseEvent(m_hExitEvent);
    ShutDownSocket();
    CloseSocekt();
    m_szDestAddr[0] = '\0';   
    m_Socket = 0;
    m_hExitEvent = 0;
    //    if(m_hExitEvent != (WSAEVENT)0xcccccccc)WSACloseEvent(m_hExitEvent);
}
bool CClientSocket::CreateSocket(SOCKET *pNewSocket,int iSockType)
{
    if(m_hExitEvent != NULL)
        WSACloseEvent(m_hExitEvent);
    m_hExitEvent=WSACreateEvent();
    WSAResetEvent(m_hExitEvent);
    bool bok =  ((*pNewSocket=WSASocket(AF_INET,iSockType,0,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)?
        false:true;
    if(bok)
    {
        int nrcvbuf=1024*68;
        int     err=setsockopt(*pNewSocket, SOL_SOCKET, SO_RCVBUF,(char*)&nrcvbuf, sizeof(nrcvbuf));
        err=setsockopt(*pNewSocket, SOL_SOCKET, SO_SNDBUF,(char*)&nrcvbuf, sizeof(nrcvbuf));

        int TimeOut=10000; //设置发送超时6秒
        if(::setsockopt(*pNewSocket,SOL_SOCKET,SO_SNDTIMEO,(char *)&TimeOut,sizeof(TimeOut))==SOCKET_ERROR){
            return 0;
        }
        TimeOut=10000;//设置接收超时6秒
        if(::setsockopt(*pNewSocket,SOL_SOCKET,SO_RCVTIMEO,(char *)&TimeOut,sizeof(TimeOut))==SOCKET_ERROR){
            return 0;
        }

    }
    return bok;
}
bool CClientSocket::BindSocket(SOCKET BindSocket,char *szHostAddr,unsigned short iHostPort)
{
    struct sockaddr_in inAddr;
    inAddr.sin_addr.S_un.S_addr=inet_addr(szHostAddr);
    inAddr.sin_family=AF_INET;
    inAddr.sin_port=htons(iHostPort);
    return (bind(BindSocket,(PSOCKADDR)&inAddr,sizeof(inAddr)))
        ==SOCKET_ERROR?false:true;
}
bool CClientSocket::ShutDownSocket(SOCKET nowSocket)
{
    if(nowSocket)
        return shutdown(nowSocket,SD_BOTH)?false:true;
    return true;
}
bool CClientSocket::CloseSocket(SOCKET nowSocket)
{
    bool bok = false;
    if(nowSocket)
        bok =  (closesocket(nowSocket)==SOCKET_ERROR)?false:true;
    m_Socket = 0;
    return bok;
}
bool CClientSocket::SendData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time)
{
    if((int)len <= 0 || len > 4096)
        return true;
    WSABUF DataBuf;
    WSAEVENT hEvents[2];
    WSAOVERLAPPED SendOverLapp;
    DWORD flag;
    char outData[4096];
    long outLen = 4096;
    if(m_bEnData)
    {
        EnData(data, len, outData, outLen);
        DataBuf.buf=outData;
        DataBuf.len=outLen;

    }
    else
    {
        DataBuf.buf=data;
        DataBuf.len=len;
    }
    hEvents[0]=m_hExitEvent;
    hEvents[1]=hSendEvent;
    memset(&SendOverLapp,0,sizeof(WSAOVERLAPPED));
    SendOverLapp.hEvent=hSendEvent;
    flag=0;
    /////////////////////////////////////
    //Godzilar
    int ret;
    if((ret=WSASend(socket,&DataBuf,1,retlen,flag,&SendOverLapp,NULL))==0)
    {
        *retlen = len;
        return true;
    }
    else if((ret==SOCKET_ERROR)&&(WSAGetLastError()==WSA_IO_PENDING))
    {
        DWORD EventCaused=WSAWaitForMultipleEvents(2,hEvents,FALSE,time,FALSE);
        WSAResetEvent(hSendEvent);
        if(EventCaused == WSA_WAIT_FAILED || EventCaused == WAIT_OBJECT_0)
        {
            if(EventCaused == WAIT_OBJECT_0)
                SetLastError(CLIENT_FUNERROR);
            return false;
        }
        flag=0;
        return WSAGetOverlappedResult(socket,&SendOverLapp,retlen,false,&flag)?
            true:false;
    }
    else
        return false;
}
bool CClientSocket::RecvData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time)
{
    WSABUF DataBuf;
    WSAEVENT hEvents[2];
    WSAOVERLAPPED RecvOverLapp;
    DWORD flag;

    hEvents[0]=m_hExitEvent;
    hEvents[1]=hRecvEvent;
    DataBuf.buf=data;
    DataBuf.len=len;
    memset(&RecvOverLapp,0,sizeof(WSAOVERLAPPED));
    RecvOverLapp.hEvent=hRecvEvent;
    flag=0;
    /////////////////////////////////////
    int ret;
    if((ret=WSARecv(socket,&DataBuf,1,retlen,&flag,&RecvOverLapp,NULL))==0)
    {
        return true;
    }
    else if((ret==SOCKET_ERROR)&&(WSAGetLastError()==WSA_IO_PENDING))
    {
        DWORD EventCaused=WSAWaitForMultipleEvents(2,hEvents,false,time,false);
        WSAResetEvent(hRecvEvent);
        if(EventCaused == WSA_WAIT_FAILED || EventCaused == WAIT_OBJECT_0)
        {
            if(EventCaused == WAIT_OBJECT_0)
                SetLastError(CLIENT_FUNERROR);
            return false;
        }
        flag=0;
        return WSAGetOverlappedResult(socket,&RecvOverLapp,retlen,false,&flag)?
            true:false;
    }
    else
        return false;
}
bool CClientSocket::SendDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time)
{
    DWORD left,idx,thisret;
    left=len;
    idx=0;
    int oflag=0;
    while(left>0)
    {
        if(!SendData(socket,&data[idx],left,&thisret,hSendEvent,time))
        {
            *retlen=0;
            return false;
        }
        WSAResetEvent(hSendEvent);
        left-=thisret;
        idx+=thisret;
        if(thisret==0)
        {
            oflag++;
            if(oflag>5)
                break;
        }
    }
    *retlen=idx;
    return (idx==len)?true:false;
}
bool CClientSocket::RecvDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time)
{
    DWORD left,idx,thisret;
    left=len;
    idx=0;
    int oflag=0;
    while(left>0)
    {
        if(!RecvData(socket,&data[idx],left,&thisret,hRecvEvent,time))
        {
            *retlen=0;
            return false;
        }
        WSAResetEvent(hRecvEvent);
        left-=thisret;
        idx+=thisret;
        if(thisret==0)
        {
            oflag++;
            if(oflag>5)
                break;
        }
    }
    *retlen=idx;
    return (idx==len)?true:false;
}
bool CClientSocket::SendMsg(char * data,DWORD len,DWORD *retlen,DWORD time)
{
    WSAEVENT hEvent=WSACreateEvent();
    bool bSend=SendDataS(m_Socket,data,len,retlen,hEvent,time);
    WSACloseEvent(hEvent);
    return bSend;
}
bool CClientSocket::RecvMsg(char * data,DWORD len,DWORD *retlen,DWORD time)
{   
    WSAEVENT hEvent=WSACreateEvent();
    bool Recv=RecvData(m_Socket,data,len,retlen,hEvent,time);
    WSACloseEvent(hEvent);
    return Recv;
}
bool CClientSocket::ConnectSocket(char * szDestAddr,unsigned short iDestPort)
{
    inAddr.sin_family=AF_INET;
    inAddr.sin_port=htons(iDestPort);
    inAddr.sin_addr.S_un.S_addr=inet_addr(szDestAddr);
    if (inAddr.sin_addr.s_addr == INADDR_NONE)
    {
        LPHOSTENT lphost;
        lphost = gethostbyname(szDestAddr);
        if (lphost != NULL)
            inAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
        else
        {
            WSASetLastError(WSAEINVAL);
            return FALSE;
        }
    }
    strcpy(m_szDestAddr, szDestAddr);
    //设置非阻塞方式连接
    unsigned long ul = 1;
    int ret = ioctlsocket(m_Socket, FIONBIO, (unsigned long*)&ul);
    if(ret==SOCKET_ERROR) return 0;

    bool bOK = (connect(m_Socket,(PSOCKADDR)&inAddr,sizeof(inAddr)))
        ==SOCKET_ERROR ? false:true;
    if(bOK)
    {
        unsigned long ul1= 0 ;
        ret = ioctlsocket(m_Socket, FIONBIO, (unsigned long*)&ul1);
        return bOK;
    }

    //select 模型,即设置超时
    struct timeval timeout ;
    fd_set r;

    FD_ZERO(&r);
    FD_SET(m_Socket, &r);
    timeout.tv_sec = 4; //连接超时15秒
    timeout.tv_usec =50000;
    ret = select(0, 0, &r, 0, &timeout);
    if ( ret <= 0 )
    {
        bOK = false;
    }
    else
        bOK = true;

    //一般非锁定模式套接比较难控制,可以根据实际情况考虑 再设回阻塞模式
    unsigned long ul1= 0 ;
    ret = ioctlsocket(m_Socket, FIONBIO, (unsigned long*)&ul1);
    if(ret==SOCKET_ERROR){
        bOK = false;
    }

    return bOK;
}

////////////////////////////////////////////////////////////////////////////////////

posted on 2012-10-11 17:34 Enic 阅读(363) 评论(0)  编辑 收藏 引用 所属分类: 代码片段分享

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理