WSAEventSelect模型:(异步IO模型)以事件形式进行通知
int WSAEventSelect(SOCKET s, WSAEvent hEventObject, long lNetworkEvents)
套接字, 与网络事件集合相关联的事件对象句柄, 感兴趣的网络事件集合
基本流程:为感兴趣的网络事件集合创建一个事件对象,调用WSAEventSelect将网络事件和事件对象关联起来。当网络事件发生时,
winsock使响应的事件对象受信,在事件对象上等待的函数会立即返回。再调用WSAEnumNetworkEvents函数就可以获得到底发生了什么网络事件.
WSACreateEvent()
WSAResetEvent()
WSASetEvent()
WSACloseEvent()
WSAWaitForMultipEvents()
WSAEnumNetworkEvents()
#include <WinSock2.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main()
{
//事件句柄和套接字句柄
WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];
SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS];
int nEventTotal = 0; //注册事件的总数
USHORT nPort = 9990; //服务器端口号
//初始化Winsockets环境
WSADATA ws;
WSAStartup(MAKEWORD(2,2), &ws);
SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(nPort);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if (::bind(sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
{
std::cout << "failed" << std::endl;
return -1;
}
::listen(sListen, 5);
//创建事件对象
WSAEVENT event = ::WSACreateEvent();
::WSAEventSelect(sListen, event, FD_ACCEPT | FD_CLOSE);
//分别放到数组中
eventArray[nEventTotal] = event;
sockArray[nEventTotal] = sListen;
nEventTotal++;
while (true)
{
//在所有事件对象上等待
int nIndex = ::WSAWaitForMultipleEvents(nEventTotal, eventArray, FALSE, WSA_INFINITE, FALSE);
//任一事件变成授信状态就返回 事件对象的句柄
nIndex = nIndex - WSA_WAIT_EVENT_0; //发生的事件对象的索引
//循环处理后面的事件对象
for (int i = nIndex; i < nEventTotal; ++i)
{
int ret;
ret = ::WSAWaitForMultipleEvents(1, &eventArray[i], TRUE, 1000, FALSE);
if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT)
{
continue;
}
else //表明有事件授信
{
WSANETWORKEVENTS event1;
::WSAEnumNetworkEvents(sockArray[i], eventArray[i], &event1);
if (event1.lNetworkEvents & FD_ACCEPT)
{
if (nEventTotal > WSA_MAXIMUM_WAIT_EVENTS)
{
cout << "连接了好多的样子" << endl;
continue;
}
SOCKET sNew = ::accept(sListen, NULL, NULL); //不用关心客户端的地址,所以直接为空吧
WSAEVENT wsaEvent = ::WSACreateEvent();
::WSAEventSelect(sNew, wsaEvent, FD_READ | FD_WRITE | FD_CLOSE);
eventArray[nEventTotal] = wsaEvent;
sockArray[nEventTotal] = sNew;
nEventTotal++;
}
else if(event1.lNetworkEvents & FD_READ) //开始读东西了
{
if (event1.iErrorCode[FD_READ_BIT] == 0)
{
char szText[256];
int nRecv = ::recv(sockArray[i], szText, strlen(szText), 0);
if (nRecv > 0)
{
szText[nRecv] = '\0';
cout << "提取到数据:" << szText << endl;
strcpy(szText, "数据已经收到");
int nSnd = ::send(sockArray[i], szText, strlen(szText), 0); //发送是非阻塞的,直接返回掉
}
}
}
else if (event1.lNetworkEvents & FD_CLOSE)
{
//关闭socket了
if (event1.iErrorCode[FD_CLOSE_BIT] == 0)
{
::closesocket(sListen);
for (int j = i; j < nEventTotal - 1; j++)
{
sockArray[j] = sockArray[j + 1]; //把这个socket从数组里删除掉,数组肯定要移动位置3
}
nEventTotal--;
}
}
else if(event1.lNetworkEvents & FD_WRITE) //由服务端程序自身触发
{
if (event1.iErrorCode[FD_WRITE_BIT] == 0)
{
char szText[256] = "嘿嘿,已经收到了哈";
int nSnd = ::send(sockArray[i], szText, strlen(szText), 0);
}
}
}
}
}
}
嘿嘿。如果是UDP的话(赶脚好高端的样子).就只监听FD_READ | FD_CLOSE了。。。。