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