【整理】重叠IO模型的编程思路及C++源代码

来源:互联网 发布:淘宝评价什么时候生效 编辑:程序博客网 时间:2024/05/17 08:19

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

 

SockObject.h

#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

OverObject.h

#include <winsock2.h>#include <iostream>using namespace std;/*******************************************************************************数据结构名称: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

Overlapped.h

#include <winsock2.h>#include "OverObject.h"#include "SockObject.h"#include <list>#include <vector>using namespace std;/*******************************************************************************类名称: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 0