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