当一个FD_XXX网络事件发生时,WSAEventSelect()函数将导致一个应用程序指定的事件对象被设置,将网络事件投递到一个事件对象句柄。
传输服务提供者会记住每个特定的FD_XXX网络事件的发生。应用程序可以调用WSAEnumNetworkEvents()函数把目前的网络事件记忆拷贝到应用程序提供的缓冲区中,并且自动清除网络事件记忆。如果需要,应用程序还可以把某个特定的时间对象和网络事件一起清除。
源代码如下
一、客户端
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#define BUFFER_SIZE 1024
int main(int argc, char **argv)
{
WSADATA wsaData;
sockaddr_in ser;
SOCKET sClient;
char send_buf[] = "hello, I am a client";
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("WSAStartup()/n");
return 0;
}
ser.sin_family = AF_INET;
ser.sin_port = htons(5050);
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
sClient = socket(AF_INET, SOCK_STREAM, 0);
if (sClient == INVALID_SOCKET)
{
printf("socket()/n");
return 0;
}
if (connect(sClient, (sockaddr*)&ser, sizeof(ser)) == INVALID_SOCKET)
{
printf("socket()/n");
return 0;
}
else
{
for (int i = 0; i < 10; i++)
{
int iLen = send(sClient, send_buf, sizeof(send_buf), 0);
if (iLen == 0)
{
return 0;
}
else if (iLen == SOCKET_ERROR)
{
printf("send()/n");
return 0;
}
}
}
closesocket(sClient);
WSACleanup();
return 0;
}
二、服务器端
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#define BUFFER_SIZE 1024
void CompressArrays(WSAEVENT events[], SOCKET sockets[], DWORD *total, int index)
{
for (size_t i = index + 1; i < *total; i++)
{
events[i - 1] = events[i];
}
*total--;
}
int main(int argc, char **argv)
{
WSADATA wsaData;
char buffer[BUFFER_SIZE];
sockaddr_in InternetAddr;
SOCKET SocketArray[WSA_MAXIMUM_WAIT_EVENTS];
WSANETWORKEVENTS NetworkEvents;
WSAEVENT NewEvent;
WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
SOCKET Accept, Listen;
DWORD EventTotal = 0;
DWORD Index;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("WSAStartup()/n");
return 0;
}
// 创建一个流式套接口
Listen = socket(AF_INET, SOCK_STREAM, 0);
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(5050);
if (bind(Listen, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
printf("bind()/n");
return 0;
}
// 创建一个事件对象
NewEvent = WSACreateEvent();
// 在Listen套接口上注册套接口连接和关闭的网络事件
WSAEventSelect(Listen, NewEvent, FD_ACCEPT | FD_CLOSE);
if (listen(Listen, 5) == SOCKET_ERROR)
{
printf("listen()/n");
return 0;
}
SocketArray[EventTotal] = Listen;
EventArray[EventTotal] = NewEvent;
EventTotal++;
while (true)
{
// 在所有套接口上等待网络事件的发生
Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);
if (WSAEnumNetworkEvents(SocketArray[Index - WSA_WAIT_EVENT_0],
EventArray[Index - WSA_WAIT_EVENT_0],
&NetworkEvents) == SOCKET_ERROR)
{
printf("%d/n", WSAGetLastError());
printf("WSAEnumNetworkEvents()/n");
return 0;
}
// 检查FD_ACCEPT
if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
{
if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] != 0)
{
WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
printf("FD_ACCEPT failed with error %d/n", NetworkEvents.iErrorCode[FD_ACCEPT_BIT]);
break;
}
// 接收新的连接,并将其存入套接口数组
Accept = accept(SocketArray[Index - WSA_WAIT_EVENT_0], NULL, NULL);
// 当套接口的数量超界时,关闭该套接口
if (EventTotal > WSA_MAXIMUM_WAIT_EVENTS)
{
printf("Too many connections");
closesocket(Accept);
break;
}
NewEvent = WSACreateEvent();
if (NewEvent == WSA_INVALID_EVENT)
{
printf("WSACreateEvent()/n");
break;
}
WSAEventSelect(Accept, NewEvent, FD_READ | FD_WRITE | FD_CLOSE);
EventArray[EventTotal] = NewEvent;
SocketArray[EventTotal] = Accept;
EventTotal++;
printf("Socket %d connected/n", Accept);
}
// 一下处理FD_READ通知
if (NetworkEvents.lNetworkEvents & FD_READ)
{
if (NetworkEvents.iErrorCode[FD_READ_BIT] != 0)
{
WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
printf("FD_READ failed with error %d/n", NetworkEvents.iErrorCode[FD_READ_BIT]);
break;
}
// 从套接口读入数据
int iRecv = recv(SocketArray[Index - WSA_WAIT_EVENT_0], buffer, sizeof(buffer), 0);
if (iRecv == 0)
{
break;
}
else if (iRecv == SOCKET_ERROR)
{
printf("recv()/n");
break;
}
else
{
printf("recv data: %s", buffer);
}
}
// 以下处理FD_WRITE通知
if (NetworkEvents.lNetworkEvents & FD_WRITE)
{
if (NetworkEvents.iErrorCode[FD_WRITE_BIT] != 0)
{
WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
printf("FD_WRITE failed with error %d/n", NetworkEvents.iErrorCode[FD_WRITE_BIT]);
break;
}
send(SocketArray[Index - WSA_WAIT_EVENT_0], buffer, sizeof(buffer), 0);
}
// 以下处理FD_CLOSE通知
if (NetworkEvents.lNetworkEvents & FD_CLOSE)
{
if (NetworkEvents.iErrorCode[FD_WRITE_BIT] != 0)
{
WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
printf("FD_WRITE faield with error %d/n", NetworkEvents.iErrorCode[FD_WRITE_BIT]);
break;
}
// 关闭套接口
closesocket(SocketArray[Index - WSA_WAIT_EVENT_0]);
// 从套接口事件和事件数组中删除关闭的套接口的有关信息
CompressArrays(EventArray, SocketArray, &EventTotal, Index - WSA_WAIT_EVENT_0);
}
}
WSACleanup();
return 0;
}