重叠IO模型(之二)

    技术2025-08-14  10

    三、编程步骤1、创建一个套接字,开始在指定的端口上监听连接请求。2、接收一个入站的连接请求。3、为接受的套接字创建新的WSAOVERLAPPED结构,并分配事件对象句柄。4、以WSAOVERLAPPED结构为参数,在套接字上投递WSARecv调用。5、将所有接受套接字的事件组建事件数组,并调用WSAWaitForMultipleEvents函数,等待与重叠调用关联在一起的事件受信。6、使用WSAGetOverlappedResult函数,判断重叠调用的返回状态。7、重新组建事件数组。8、在套接字上重投递WSARecv请求。9、重复5~8。

    例子:初步封装了OverLapped类

    /*SockObject*/#include <winsock2.h>

    class SockObject{public:        SOCKET m_sock;        int m_operatNum;public:        SockObject(void);        SockObject(SOCKET mySock);        SockObject(SockObject &mySockObject);        ~SockObject(void);};

    SockObject::SockObject(SOCKET mySock){        m_sock = mySock;        m_operatNum = 0;}

    SockObject::SockObject(SockObject &mySockObject){        m_sock = mySockObject.m_sock;        m_operatNum = mySockObject.m_operatNum;}/*******************************************************************************数据结构名称:OverObject*功能:记录一个套接字的一个操作、一个事件和一个重叠I/O的关联*****************************************************************************/class OverObject{public:SOCKET m_sock;                                  /*绑定的套接字*/        OVERLAPPED m_overlapped;                /*绑定的重叠I/O*/        char *m_buf;                            /*用于存放数据的缓冲区*/        int m_len;                              /*缓冲区的长度*/        int m_operation;                        /*套接字针对的操作*/public:        bool operator==(const OverObject &myOverObject) const;public:        OverObject(void);        OverObject(const OverObject &myOverObject);        OverObject(SOCKET mySock, int myLen);        ~OverObject(void);};

    /*定义指向重叠对象的指针类型*/typedef OverObject * PtrOverObject;

    OverObject::~OverObject(void){        delete m_buf;}

    /********************************************************************************* 函数介绍:本函数是OverObject类的复制构造函数。*********************************************************************************/OverObject::OverObject(const OverObject &myOverObject){        m_sock = myOverObject.m_sock;                        m_overlapped = myOverObject.m_overlapped;        m_buf = new char[myOverObject.m_len];        strcpy(m_buf,myOverObject.m_buf);                        m_len = myOverObject.m_len;                        m_operation = myOverObject.m_operation;}

    /********************************************************************************* 函数介绍:本函数是OverObject类带参数的构造函数。*********************************************************************************/OverObject::OverObject(SOCKET mySock, int myLen){        m_sock = mySock;        m_buf = new char[myLen];        m_len = myLen;        m_overlapped.hEvent = ::WSACreateEvent();}

    /********************************************************************************* 函数介绍:本函数是OverObject类的==运算符重载函数*********************************************************************************/bool OverObject::operator==(const OverObject &myOverObject) const{        if(this->m_sock == myOverObject.m_sock && this->m_operation == myOverObject.m_operation && this->m_len == myOverObject.m_len && !strcmp(this->m_buf, myOverObject.m_buf))        {                        cout << "the two overObject is eque !" << endl;                return true;        }        else        {                return false;        }}

     

    /*******************************************************************************类名称:Overlapped*功能:记录系统中需要维护的所有重叠I/O*****************************************************************************/#define OP_ACCEPT 1#define OP_READ   2#define OP_WRITE 3

    class Overlapped{public:        list<OverObject> overObjects;                /*需要维护的所有重叠I/O*/        vector<HANDLE> eventArray;                   /*所有重叠I/O所对应的事件组成的数组,作为等待函数的参数*/        vector<SockObject> sockArray;                /*需要维护的所有套接字,当操作为零时关闭套接字*/public:        list<OverObject>::iterator GetOverObject(SOCKET mySock, int myLen);        void FreeOverObject(list<OverObject>::iterator myPtrOverObject);        list<OverObject>::iterator Overlapped::FindOverObject(HANDLE myEvent);        void RebuildEventArray();        void CreateAcceptEvent();        void SetAcceptEvent();        void ResetAcceptEvent();        bool IsAcceptEvent(int index);

            bool PostRecv(list<OverObject>::iterator myPtrOverObject);        bool PostSend(list<OverObject>::iterator myPtrOverObject);        bool PostAccept(list<OverObject>::iterator myPtrOverObject);

            Overlapped(void);        ~Overlapped(void);

            void InitSocket();};

    /********************************************************************************* 函数介绍:创建重叠对象的类对象,并插入重叠对象链表中。*********************************************************************************/list<OverObject>::iterator Overlapped::GetOverObject(SOCKET mySock, int myLen){        OverObject localOverObject(mySock, myLen);        overObjects.push_back(localOverObject);        eventArray.push_back(localOverObject.m_overlapped.hEvent);        list<OverObject>::iterator ret = overObjects.end();        ret--;        return ret; }

    /********************************************************************************* 函数介绍:释放重叠对象链表中指定的重叠对象。*********************************************************************************/void Overlapped::FreeOverObject(list<OverObject>::iterator myPtrOverObject){        overObjects.erase(myPtrOverObject);}

    /********************************************************************************* 函数介绍:从重叠对象列表中查找指定事件所对应的重叠对象。*********************************************************************************/list<OverObject>::iterator Overlapped::FindOverObject(HANDLE myEvent){        list<OverObject>::iterator localIerator;        for(localIerator = overObjects.begin(); localIerator != overObjects.end(); localIerator++)        {                if(localIerator->m_overlapped.hEvent == myEvent)                {                        break;                }        }

            return localIerator;}

    /********************************************************************************* 函数介绍:遍历重叠对象列表,重建重叠对象列表所对应的事件数组。*********************************************************************************/void Overlapped::RebuildEventArray(){        eventArray.clear();        list<OverObject>::iterator overObjIterator;        overObjIterator = overObjects.begin();        for(overObjIterator; overObjIterator != overObjects.end(); ++overObjIterator)        {                eventArray.push_back(overObjIterator->m_overlapped.hEvent);        }}

    /********************************************************************************* 函数介绍:投放接受操作,即将指定套接字的Recv操作与重叠I/O对象关联起来。*********************************************************************************/bool Overlapped::PostRecv(list<OverObject>::iterator myPtrOverObject){        myPtrOverObject->m_operation = OP_READ;

            DWORD dwBytes;        DWORD dwFlags = 0;        WSABUF buf;        buf.buf = myPtrOverObject->m_buf;        buf.len = myPtrOverObject->m_len;        memset(buf.buf, 0, buf.len);                if(::WSARecv(myPtrOverObject->m_sock, &buf, 1, &dwBytes, &dwFlags, &myPtrOverObject->m_overlapped,NULL)!=NO_ERROR)        {                if(::WSAGetLastError() != WSA_IO_PENDING)                {                        return false;                }        }

            return true;}

    /********************************************************************************* 函数介绍:投放发送操作,即将指定套接字的Send操作与重叠I/O对象关联起来。*********************************************************************************/bool Overlapped::PostSend(list<OverObject>::iterator myPtrOverObject){        myPtrOverObject->m_operation = OP_WRITE;

            DWORD dwBytes;        DWORD dwFlags = 0;        WSABUF buf;        buf.buf = myPtrOverObject->m_buf;        buf.len = myPtrOverObject->m_len;        if(::WSASend(myPtrOverObject->m_sock, &buf, 1, &dwBytes, dwFlags, &myPtrOverObject->m_overlapped,NULL)!=NO_ERROR)        {                if(::WSAGetLastError() != WSA_IO_PENDING)                {                        return false;                }        }

            return true;}

    /********************************************************************************* 函数介绍:创建accept函数完成事件,用于处理accepe后等待函数的等待事件句柄数组发            生变化,若此时无事件触发,等待事件句柄数组仍以原来的事件句柄数组为依            据等待。*********************************************************************************/void Overlapped::CreateAcceptEvent(){        //标志套接字,用于触发accept完成事件。        SOCKET myClient = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);        list<OverObject>::iterator acceptIterator = GetOverObject(myClient, 512);        RebuildEventArray();}

    /********************************************************************************* 函数介绍:当accept函数完成时,重置accept所对应的事件,从而使得等待函数能够在改            变后的事件句柄数组上等待。*********************************************************************************/void Overlapped::SetAcceptEvent(){        ::SetEvent(eventArray.front());}

    void Overlapped::ResetAcceptEvent(){        ::ResetEvent(eventArray.front());}

    bool Overlapped::IsAcceptEvent(int index){        if(index == 0)        {                return true;        }        else        {                return false;        }}

    /*主程序*/#include "Overlapped.h"

    #include <windows.h>#include <process.h>

    bool OperateFunction(PtrOverObject myPtrOverObject);UINT WINAPI ServerThread(PVOID pvParam);

    Overlapped myOverlapped;

    int main(){        WSADATA wsaData;        if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)        {                cout<<"failed to load winsock !"<<endl;                exit(0);        }                SOCKET mylisten, myClient;        mylisten = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);                struct sockaddr_in localAddr, clientAddr;        localAddr.sin_family = AF_INET;        localAddr.sin_port = ntohs(5500);        localAddr.sin_addr.S_un.S_addr = inet_addr("59.73.161.221");                bind(mylisten, (sockaddr*)&localAddr, sizeof(localAddr));        listen(mylisten, 5);                        int sizeAddr = sizeof(clientAddr);        cout << "server is listening......" << endl;

            myOverlapped.CreateAcceptEvent();

            int x;        _beginthreadex(NULL, 0, ServerThread, &x, 0, NULL);       

            /*循环接收客户端的连接,创建与客户端通信的重叠IO对象,并重建事件句柄数组*/        while(true)        {                myClient = accept(mylisten, (struct sockaddr*)&clientAddr, &sizeAddr);

                    if(myClient==INVALID_SOCKET)                {                        cout<<"accept is failed !"<<endl;                        return -1;                }

                    list<OverObject>::iterator localIterator = myOverlapped.GetOverObject(myClient, 512);                myOverlapped.PostRecv(localIterator);                myOverlapped.RebuildEventArray();                myOverlapped.SetAcceptEvent();        }        char ch;        cin >> ch;        return 0;}

    /********************************************************************************* 函数介绍:数据处理函数,按照不同操作类型,处理数据的发送或接受。*********************************************************************************/bool OperateFunction(list<OverObject>::iterator myOverObjectIterator){        DWORD dwTrans;        DWORD dwFlags;        BOOL ret = ::WSAGetOverlappedResult(myOverObjectIterator->m_sock, &(myOverObjectIterator->m_overlapped), &dwTrans, false, &dwFlags);        if(!ret)        {                if(myOverObjectIterator->m_sock != INVALID_SOCKET)                {                        closesocket(myOverObjectIterator->m_sock);                }                cout << "socket error : " << ::GetLastError() << endl;                myOverlapped.FreeOverObject(myOverObjectIterator);                myOverlapped.RebuildEventArray();                return false;        }        switch(myOverObjectIterator->m_operation)        {        case OP_READ:        /*接收数据完成*/                if(dwTrans > 0)                {                        cout << myOverObjectIterator->m_buf << endl;                        list<OverObject>::iterator localIterator = myOverlapped.GetOverObject(myOverObjectIterator->m_sock, 512);                        localIterator->m_len = myOverObjectIterator->m_len;                        strcpy(localIterator->m_buf, myOverObjectIterator->m_buf);                        myOverlapped.PostSend(localIterator);                        myOverlapped.RebuildEventArray();                        return true;                }                else                {                        closesocket(myOverObjectIterator->m_sock);                        myOverlapped.FreeOverObject(myOverObjectIterator);                        myOverlapped.RebuildEventArray();                        cout << "the client socket is close !" << endl;                        return false;                }                break;        case OP_WRITE:                /*发送数据完成*/                if(dwTrans > 0)                {                        return true;                }                else                {                        closesocket(myOverObjectIterator->m_sock);                        myOverlapped.FreeOverObject(myOverObjectIterator);                        myOverlapped.RebuildEventArray();                        return false;                }                break;        }}

    /********************************************************************************* 函数介绍:服务线程函数,平常处于等待状态,完成数据处理。*********************************************************************************/UINT WINAPI ServerThread(PVOID pvParam){        while(true)        {                int index;                DWORD eventNum = (DWORD)(myOverlapped.eventArray.size());

                    index = ::WSAWaitForMultipleEvents(eventNum, &(myOverlapped.eventArray[0]), false, WSA_INFINITE, false);

                    if(index == WSA_WAIT_FAILED)                {                        cout << "wait error is : " << ::GetLastError() << endl;                        break;                }

                    else                {                        index = index - WSA_WAIT_EVENT_0;                        if(myOverlapped.IsAcceptEvent(index))                        {                                myOverlapped.ResetAcceptEvent();                                continue;                        }                        list<OverObject>::iterator nowIterator = (myOverlapped.FindOverObject(myOverlapped.eventArray[index]));                        if(nowIterator != NULL)                        {                                bool ret = OperateFunction(nowIterator);                                if(ret)                                {                                        ::WSAResetEvent(myOverlapped.eventArray[index]);                                        myOverlapped.PostRecv(nowIterator);                                }                        }                }        }        return 0;}

    最新回复(0)