重叠IO模型(之二)

来源:互联网 发布:淘宝店名会侵权吗 编辑:程序博客网 时间:2024/05/16 07:44

三、编程步骤
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;
}

原创粉丝点击