Windows网络编程之事件选择模型(三)
一、WSACreateEvent函数
WSACreateEvent函数是Windows套接字API中的一部分,它用于创建套接字事件对象,以便在套接字操作上等待事件发生。这个函数通常与异步套接字操作一起使用,以允许应用程序异步地等待套接字事件的发生,而不需要阻塞线程。
函数原型:
WSAEVENT WSAAPI WSACreateEvent(void);
参数:
无需传递任何参数。
返回值:
- 如果成功,函数返回一个
WSAEVENT类型的句柄,代表创建的套接字事件对象。 - 如果失败,函数返回
WSA_INVALID_EVENT,并且可以通过WSAGetLastError()函数获取错误代码。
二、WSAEventSelect函数
WSAEventSelect函数是Windows套接字编程中常用的函数,用于指定一个或多个事件,以便在套接字上等待这些事件的发生。这个函数通常与异步套接字一起使用,以允许应用程序在等待事件发生时不会阻塞线程。
函数原型:
int WSAEventSelect( SOCKET s, WSAEVENT hEventObject, long lNetworkEvents );
参数:
s:要关联事件的套接字的描述符。hEventObject:一个套接字事件对象的句柄,通常通过WSACreateEvent函数创建。lNetworkEvents:一个标志位,用于指定要关联的事件类型。可以使用各种常量来设置这些标志,例如FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT等。- FD_ACCEPT:有客户端链接,与服务器socket绑定。
- FD_READ:有客户端发来消息,与客户端socket绑定,可多个属性并列用。
- FD_CLOSE:客户端下线,与客户端socket绑定,包含强制下线,正常下线。
- FD_WRITE:可以给客户端发送信息,与客户端socket绑定,会在accept后立即主动产生该信号,可以说明,客户端链接成功,即可随时发送信息。
- FD_CONNECT:客户端一方,给服务器绑定这个。
- 0:取消事件监视
返回值:
- 如果函数成功,返回值为0。
- 如果函数失败,返回值为
SOCKET_ERROR,并且可以通过WSAGetLastError()函数获取错误代码。
三、WSAWaitForMultipleEvents函数
WSAWaitForMultipleEvents函数是Windows套接字编程中用于等待多个套接字事件的函数。它允许应用程序等待一个或多个套接字事件对象的发生,而不需要阻塞线程。这个函数通常与WSAEventSelect函数结合使用,以便在异步套接字编程中有效地等待事件。
函数原型:
DWORD WSAWaitForMultipleEvents( DWORD cEvents, const WSAEVENT *lphEvents, BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable );
参数:
cEvents:待等待的事件数量,即事件对象数组的大小。lphEvents:一个指向WSAEVENT数组的指针,其中包含要等待的事件对象的句柄。fWaitAll:一个布尔值,用于指定是等待所有事件发生(TRUE)还是等待任意一个事件发生(FALSE)。dwTimeout:等待事件的超时时间,以毫秒为单位。如果设置为WSA_INFINITE,则表示无限等待;设置为0,表示检查事件对象的状态并立即返回,不管有没有信号。fAlertable:一个布尔值,指示是否允许在等待期间响应异步I/O完成通知。
返回值:
- 如果函数成功,返回值是一个非负整数,表示事件对象数组中第一个满足条件的事件的索引。返回值减去 WSA_WAIT_EVENT_0 表示其状态导致函数返回的事件对象的索引。如果在调用期间有多个事件对象发出信号,则这是发出信号的事件对象的数组索引,其中索引值是所有发出信号的事件对象中最小的。。
- 如果函数失败,返回值为
WAIT_FAILED,可以通过GetLastError()函数获取错误代码。 - 如果返回值为WSA_WAIT_TIMEOUT,则表示等待超时。
四、WSAEnumNetworkEvents函数
该函数发现指定套接字的网络事件的发生,清除内部网络事件记录,并重置事件对象。
函数原型:
int WSAEnumNetworkEvents( SOCKET s, WSAEVENT hEventObject, LPWSANETWORKEVENTS lpNetworkEvents );
参数:
s:要查询事件状态的套接字的描述符。hEventObject:与套接字关联的事件对象的句柄。lpNetworkEvents:一个指向WSANETWORKEVENTS结构的指针,用于存储查询结果。
WSANETWORKEVENTS结构:
typedef struct _WSANETWORKEVENTS {
long lNetworkEvents;
int iErrorCode[FD_MAX_EVENTS];
} WSANETWORKEVENTS, *LPWSANETWORKEVENTS;
结构体参数:
lNetworkEvents:一个标志位,指示已发生的网络事件类型;一个信号可能包含两个消息,以按位或的形式存在iErrorCode:一个数组,其中包含每个网络事件的错误代码;比如FD_ACCEPT事件错误码在FD_ACCEPT_BIT下标里,如果事件未发生,相应的错误代码为0。
返回值:
- 如果函数成功,返回值为0。
- 如果函数失败,返回值为
SOCKET_ERROR,并且可以通过WSAGetLastError()函数获取错
五、事件选择模型的Server源码
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
typedef struct fd_es_set {
unsigned short count;
SOCKET sockall[WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT eventall[WSA_MAXIMUM_WAIT_EVENTS];
} FD_ES;
int main() {
WSADATA wsaData; // 创建一个 WSADATA 结构
// 初始化 Winsock 库,指定要使用的版本
int ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (ret != 0) {
printf("WSAStartup 失败,错误码: %d\n", ret);
return 0;
}
//校验版本
if (HIBYTE(wsaData.wVersion) != 2 || LOBYTE(wsaData.wVersion) != 2) {
printf("版本不符合");
WSACleanup();
return 0;
}
// 在这里进行网络编程操作
SOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketServer == INVALID_SOCKET) {
int errorCode = WSAGetLastError();
printf("socket创建失败,错误码:%u\n", errorCode);
closesocket(socketServer);
WSACleanup();
}
sockaddr_in si;
si.sin_family = AF_INET;
si.sin_addr.s_addr = inet_addr("127.0.0.1");
si.sin_port = htons(1234);
ret = bind(socketServer, (SOCKADDR*)&si, sizeof(si));
if (ret == SOCKET_ERROR) {
printf("bind绑定失败,错误码:%u\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
ret = listen(socketServer, SOMAXCONN);
if (ret == SOCKET_ERROR) {
printf("listen监听失败,错误码:%u\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
FD_ES eventSet = { 0, {0}, {NULL} };
//创建事件
WSAEVENT hEvent = WSACreateEvent();
if (hEvent == WSA_INVALID_EVENT) {
printf("WSACreateEvent errCode:%d\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
ret = WSAEventSelect(socketServer, hEvent, FD_ACCEPT);
if (ret == SOCKET_ERROR) {
printf("WSACreateEvent errCode:%d\n", WSAGetLastError());
//释放事件句柄
WSACloseEvent(hEvent);
closesocket(socketServer);
WSACleanup();
return 0;
}
eventSet.eventall[eventSet.count] = hEvent;
eventSet.sockall[eventSet.count] = socketServer;
eventSet.count++;
while (true) {
DWORD dResult = WSAWaitForMultipleEvents(eventSet.count, eventSet.eventall, FALSE, WSA_INFINITE, FALSE);
if (dResult == WSA_WAIT_FAILED) {
printf("WSAWaitForMultipleEvents ErrorCode:%d\n", WSAGetLastError());
break;
}
if (dResult == WSA_WAIT_TIMEOUT) {
continue;
}
DWORD dIndex = dResult - WSA_WAIT_EVENT_0;
//得到下标对应的事件
WSANETWORKEVENTS networkEvents;
ret = WSAEnumNetworkEvents(eventSet.sockall[dIndex], eventSet.eventall[dIndex], &networkEvents);
if (ret == SOCKET_ERROR) {
printf("WSAEnumNetworkEvents ErrorCode:%d\n", WSAGetLastError());
break;
}
if (networkEvents.lNetworkEvents & FD_ACCEPT) {
if (networkEvents.iErrorCode[FD_ACCEPT_BIT] == 0) {
//正常处理
SOCKET socketClient = accept(eventSet.sockall[dIndex], NULL, NULL);
if (socketClient == INVALID_SOCKET) {
continue;
}
//创建事件对象
WSAEVENT wsaClientEvent = WSACreateEvent();
if (wsaClientEvent == WSA_INVALID_EVENT) {
closesocket(socketClient);
continue;
}
//客户端socket投递给系统
ret = WSAEventSelect(socketClient, wsaClientEvent, FD_READ | FD_WRITE | FD_CLOSE);
if (ret == SOCKET_ERROR) {
closesocket(socketClient);
WSACloseEvent(wsaClientEvent);
continue;
}
//装进结构体
eventSet.sockall[eventSet.count] = socketClient;
eventSet.eventall[eventSet.count] = wsaClientEvent;
eventSet.count++;
printf("accept event\n");
}
else {
continue;
}
}
if (networkEvents.lNetworkEvents & FD_WRITE) {
if (networkEvents.iErrorCode[FD_WRITE_BIT] == 0) {
char buffer[] = "connect success";
printf("FD_WRITE socket:%d\n", eventSet.sockall[dIndex]);
ret = send(eventSet.sockall[dIndex], buffer, strlen(buffer), 0);
if (ret == SOCKET_ERROR) {
printf("send failed, errCode:%d\n", WSAGetLastError());
continue;
}
printf("write event\n");
} else {
printf("FD_WRITE_BIT socket error code:%d\n", networkEvents.iErrorCode[FD_WRITE_BIT]);
continue;
}
}
if (networkEvents.lNetworkEvents & FD_READ) {
if (networkEvents.iErrorCode[FD_READ_BIT] == 0) {
char buffer[1024] = { 0 };
printf("FD_READ socket:%d\n", eventSet.sockall[dIndex]);
ret = recv(eventSet.sockall[dIndex], buffer, sizeof(buffer), 0);
if (ret == SOCKET_ERROR) {
printf("recv failed, errCode:%d\n", WSAGetLastError());
continue;
}
printf("recv client data:%s\n", buffer);
const char send_buff[] = "hello, I'm is server";
ret = send(eventSet.sockall[dIndex], send_buff, sizeof(send_buff), 0);
if (ret == SOCKET_ERROR) {
printf("send失败,错误码:%u\n", WSAGetLastError());
}
} else {
printf("FD_READ_BIT socket error code:%d\n", networkEvents.iErrorCode[FD_READ_BIT]);
continue;
}
}
if (networkEvents.lNetworkEvents & FD_CLOSE) {
if (networkEvents.iErrorCode[FD_CLOSE_BIT] == 0) {
printf("客户端正常退出\n");
} else {
printf("客户端异常终止,错误码:%d\n", networkEvents.iErrorCode[FD_CLOSE_BIT]);
}
//清理下线的客户端,套接字,事件
//套接字
closesocket(eventSet.sockall[dIndex]);
eventSet.sockall[dIndex] = eventSet.sockall[eventSet.count - 1];
//事件
WSACloseEvent(eventSet.eventall[dIndex]);
eventSet.eventall[dIndex] = eventSet.eventall[eventSet.count - 1];
eventSet.count--;
}
}
//释放事件句柄
WSACloseEvent(hEvent);
closesocket(socketServer);
WSACleanup();
return 1;
}
六、事件选择模型的Client源码
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
int main() {
WSADATA wsaData; // 创建一个 WSADATA 结构
// 初始化 Winsock 库,指定要使用的版本
int ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (ret != 0) {
printf("WSAStartup 失败,错误码: %d\n", ret);
return 0;
}
//校验版本
if (HIBYTE(wsaData.wVersion) != 2 || LOBYTE(wsaData.wVersion) != 2) {
printf("版本不符合");
WSACleanup();
return 0;
}
// 在这里进行网络编程操作
SOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketServer == INVALID_SOCKET) {
int errorCode = WSAGetLastError();
printf("socket创建失败,错误码:%u\n", errorCode);
closesocket(socketServer);
WSACleanup();
}
//链接服务器
sockaddr_in si;
si.sin_family = AF_INET;
si.sin_addr.s_addr = inet_addr("127.0.0.1");
si.sin_port = htons(1234);
ret = connect(socketServer, (SOCKADDR*)&si, sizeof(si));
if (ret == SOCKET_ERROR) {
printf("connect失败,错误码:%u\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
int nCount = 0;
while (true) {
if (nCount >= 5) {
break;
}
Sleep(1000);
const char send_buff[] = "hello, I'm is client";
ret = send(socketServer, send_buff, sizeof(send_buff), 0);
if (ret == SOCKET_ERROR) {
printf("send失败,错误码:%u\n", WSAGetLastError());
}
char buffer[1024] = { 0 };
ret = recv(socketServer, buffer, sizeof(buffer), 0);
if (ret == 0) {
printf("客户端连接中断\n");
}
else if (ret == SOCKET_ERROR) {
printf("recv失败,错误码:%u\n", WSAGetLastError());
}
else {
printf("recv_len:%d,recv_data:%s\n", ret, buffer);
}
nCount++;
}
closesocket(socketServer);
WSACleanup();
system("pause");
return 1;
}
七、事件选择模型的Server有序优化
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
typedef struct fd_es_set {
unsigned short count;
SOCKET sockall[WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT eventall[WSA_MAXIMUM_WAIT_EVENTS];
} FD_ES;
int main() {
WSADATA wsaData; // 创建一个 WSADATA 结构
// 初始化 Winsock 库,指定要使用的版本
int ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (ret != 0) {
printf("WSAStartup 失败,错误码: %d\n", ret);
return 0;
}
//校验版本
if (HIBYTE(wsaData.wVersion) != 2 || LOBYTE(wsaData.wVersion) != 2) {
printf("版本不符合");
WSACleanup();
return 0;
}
// 在这里进行网络编程操作
SOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketServer == INVALID_SOCKET) {
int errorCode = WSAGetLastError();
printf("socket创建失败,错误码:%u\n", errorCode);
closesocket(socketServer);
WSACleanup();
}
sockaddr_in si;
si.sin_family = AF_INET;
si.sin_addr.s_addr = inet_addr("127.0.0.1");
si.sin_port = htons(1234);
ret = bind(socketServer, (SOCKADDR*)&si, sizeof(si));
if (ret == SOCKET_ERROR) {
printf("bind绑定失败,错误码:%u\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
ret = listen(socketServer, SOMAXCONN);
if (ret == SOCKET_ERROR) {
printf("listen监听失败,错误码:%u\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
FD_ES eventSet = { 0, {0}, {NULL} };
//创建事件
WSAEVENT hEvent = WSACreateEvent();
if (hEvent == WSA_INVALID_EVENT) {
printf("WSACreateEvent errCode:%d\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
ret = WSAEventSelect(socketServer, hEvent, FD_ACCEPT);
if (ret == SOCKET_ERROR) {
printf("WSACreateEvent errCode:%d\n", WSAGetLastError());
//释放事件句柄
WSACloseEvent(hEvent);
closesocket(socketServer);
WSACleanup();
return 0;
}
eventSet.eventall[eventSet.count] = hEvent;
eventSet.sockall[eventSet.count] = socketServer;
eventSet.count++;
while (true) {
DWORD dResult = WSAWaitForMultipleEvents(eventSet.count, eventSet.eventall, FALSE, WSA_INFINITE, FALSE);
if (dResult == WSA_WAIT_FAILED) {
printf("WSAWaitForMultipleEvents ErrorCode:%d\n", WSAGetLastError());
continue;
}
DWORD dIndex = dResult - WSA_WAIT_EVENT_0;
for (int nIndex = dIndex; nIndex < eventSet.count; nIndex++) {
//得到下标对应的事件
WSANETWORKEVENTS networkEvents;
ret = WSAEnumNetworkEvents(eventSet.sockall[nIndex], eventSet.eventall[nIndex], &networkEvents);
if (ret == SOCKET_ERROR) {
printf("WSAEnumNetworkEvents ErrorCode:%d\n", WSAGetLastError());
break;
}
if (networkEvents.lNetworkEvents & FD_ACCEPT) {
if (networkEvents.iErrorCode[FD_ACCEPT_BIT] == 0) {
//正常处理
SOCKET socketClient = accept(eventSet.sockall[nIndex], NULL, NULL);
if (socketClient == INVALID_SOCKET) {
continue;
}
//创建事件对象
WSAEVENT wsaClientEvent = WSACreateEvent();
if (wsaClientEvent == WSA_INVALID_EVENT) {
closesocket(socketClient);
continue;
}
//客户端socket投递给系统
ret = WSAEventSelect(socketClient, wsaClientEvent, FD_READ | FD_WRITE | FD_CLOSE);
if (ret == SOCKET_ERROR) {
closesocket(socketClient);
WSACloseEvent(wsaClientEvent);
continue;
}
//装进结构体
eventSet.sockall[eventSet.count] = socketClient;
eventSet.eventall[eventSet.count] = wsaClientEvent;
eventSet.count++;
printf("accept event\n");
}
else {
continue;
}
}
if (networkEvents.lNetworkEvents & FD_WRITE) {
if (networkEvents.iErrorCode[FD_WRITE_BIT] == 0) {
char buffer[] = "connect success";
printf("FD_WRITE socket:%d\n", eventSet.sockall[nIndex]);
ret = send(eventSet.sockall[nIndex], buffer, strlen(buffer), 0);
if (ret == SOCKET_ERROR) {
printf("send failed, errCode:%d\n", WSAGetLastError());
continue;
}
printf("write event\n");
}
else {
printf("FD_WRITE_BIT socket error code:%d\n", networkEvents.iErrorCode[FD_WRITE_BIT]);
continue;
}
}
if (networkEvents.lNetworkEvents & FD_READ) {
if (networkEvents.iErrorCode[FD_READ_BIT] == 0) {
char buffer[1024] = { 0 };
printf("FD_READ socket:%d\n", eventSet.sockall[nIndex]);
ret = recv(eventSet.sockall[nIndex], buffer, sizeof(buffer), 0);
if (ret == SOCKET_ERROR) {
printf("recv failed, errCode:%d\n", WSAGetLastError());
continue;
}
printf("recv client data:%s\n", buffer);
const char send_buff[] = "hello, I'm is server";
ret = send(eventSet.sockall[nIndex], send_buff, sizeof(send_buff), 0);
if (ret == SOCKET_ERROR) {
printf("send失败,错误码:%u\n", WSAGetLastError());
}
}
else {
printf("FD_READ_BIT socket error code:%d\n", networkEvents.iErrorCode[FD_READ_BIT]);
continue;
}
}
if (networkEvents.lNetworkEvents & FD_CLOSE) {
if (networkEvents.iErrorCode[FD_CLOSE_BIT] == 0) {
printf("客户端正常退出\n");
}
else {
printf("客户端异常终止,错误码:%d\n", networkEvents.iErrorCode[FD_CLOSE_BIT]);
}
//清理下线的客户端,套接字,事件
//套接字
closesocket(eventSet.sockall[nIndex]);
eventSet.sockall[nIndex] = eventSet.sockall[eventSet.count - 1];
//事件
WSACloseEvent(eventSet.eventall[nIndex]);
eventSet.eventall[nIndex] = eventSet.eventall[eventSet.count - 1];
eventSet.count--;
}
}
}
//释放事件句柄
WSACloseEvent(hEvent);
closesocket(socketServer);
WSACleanup();
return 1;
}
八、增加事件处理的数量
1.扩充结构体 FD_ES中套接字SOCKET和事件WSAEVENT的容量
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
typedef struct fd_es_set {
unsigned short count;
SOCKET sockall[1024];
WSAEVENT eventall[1024];
} FD_ES;
int main() {
WSADATA wsaData; // 创建一个 WSADATA 结构
// 初始化 Winsock 库,指定要使用的版本
int ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (ret != 0) {
printf("WSAStartup 失败,错误码: %d\n", ret);
return 0;
}
//校验版本
if (HIBYTE(wsaData.wVersion) != 2 || LOBYTE(wsaData.wVersion) != 2) {
printf("版本不符合");
WSACleanup();
return 0;
}
// 在这里进行网络编程操作
SOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketServer == INVALID_SOCKET) {
int errorCode = WSAGetLastError();
printf("socket创建失败,错误码:%u\n", errorCode);
closesocket(socketServer);
WSACleanup();
}
sockaddr_in si;
si.sin_family = AF_INET;
si.sin_addr.s_addr = inet_addr("127.0.0.1");
si.sin_port = htons(1234);
ret = bind(socketServer, (SOCKADDR*)&si, sizeof(si));
if (ret == SOCKET_ERROR) {
printf("bind绑定失败,错误码:%u\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
ret = listen(socketServer, SOMAXCONN);
if (ret == SOCKET_ERROR) {
printf("listen监听失败,错误码:%u\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
FD_ES eventSet = { 0, {0}, {NULL} };
//创建事件
WSAEVENT hEvent = WSACreateEvent();
if (hEvent == WSA_INVALID_EVENT) {
printf("WSACreateEvent errCode:%d\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
ret = WSAEventSelect(socketServer, hEvent, FD_ACCEPT);
if (ret == SOCKET_ERROR) {
printf("WSACreateEvent errCode:%d\n", WSAGetLastError());
//释放事件句柄
WSACloseEvent(hEvent);
closesocket(socketServer);
WSACleanup();
return 0;
}
eventSet.eventall[eventSet.count] = hEvent;
eventSet.sockall[eventSet.count] = socketServer;
eventSet.count++;
while (true) {
for (int nIndex = 0; nIndex < eventSet.count; nIndex++) {
DWORD dResult = WSAWaitForMultipleEvents(1, &eventSet.eventall[nIndex], FALSE, 10, FALSE);
if (dResult == WSA_WAIT_FAILED) {
printf("WSAWaitForMultipleEvents ErrorCode:%d\n", WSAGetLastError());
continue;
}
if (dResult == WSA_WAIT_TIMEOUT) {
continue;
}
//得到下标对应的事件
WSANETWORKEVENTS networkEvents;
ret = WSAEnumNetworkEvents(eventSet.sockall[nIndex], eventSet.eventall[nIndex], &networkEvents);
if (ret == SOCKET_ERROR) {
printf("WSAEnumNetworkEvents ErrorCode:%d\n", WSAGetLastError());
break;
}
if (networkEvents.lNetworkEvents & FD_ACCEPT) {
if (networkEvents.iErrorCode[FD_ACCEPT_BIT] == 0) {
//正常处理
SOCKET socketClient = accept(eventSet.sockall[nIndex], NULL, NULL);
if (socketClient == INVALID_SOCKET) {
continue;
}
//创建事件对象
WSAEVENT wsaClientEvent = WSACreateEvent();
if (wsaClientEvent == WSA_INVALID_EVENT) {
closesocket(socketClient);
continue;
}
//客户端socket投递给系统
ret = WSAEventSelect(socketClient, wsaClientEvent, FD_READ | FD_WRITE | FD_CLOSE);
if (ret == SOCKET_ERROR) {
closesocket(socketClient);
WSACloseEvent(wsaClientEvent);
continue;
}
//装进结构体
eventSet.sockall[eventSet.count] = socketClient;
eventSet.eventall[eventSet.count] = wsaClientEvent;
eventSet.count++;
printf("accept event\n");
}
else {
continue;
}
}
if (networkEvents.lNetworkEvents & FD_WRITE) {
if (networkEvents.iErrorCode[FD_WRITE_BIT] == 0) {
char buffer[] = "connect success";
printf("FD_WRITE socket:%d\n", eventSet.sockall[nIndex]);
ret = send(eventSet.sockall[nIndex], buffer, strlen(buffer), 0);
if (ret == SOCKET_ERROR) {
printf("send failed, errCode:%d\n", WSAGetLastError());
continue;
}
printf("write event\n");
}
else {
printf("FD_WRITE_BIT socket error code:%d\n", networkEvents.iErrorCode[FD_WRITE_BIT]);
continue;
}
}
if (networkEvents.lNetworkEvents & FD_READ) {
if (networkEvents.iErrorCode[FD_READ_BIT] == 0) {
char buffer[1024] = { 0 };
printf("FD_READ socket:%d\n", eventSet.sockall[nIndex]);
ret = recv(eventSet.sockall[nIndex], buffer, sizeof(buffer), 0);
if (ret == SOCKET_ERROR) {
printf("recv failed, errCode:%d\n", WSAGetLastError());
continue;
}
printf("recv client data:%s\n", buffer);
const char send_buff[] = "hello, I'm is server";
ret = send(eventSet.sockall[nIndex], send_buff, sizeof(send_buff), 0);
if (ret == SOCKET_ERROR) {
printf("send失败,错误码:%u\n", WSAGetLastError());
}
}
else {
printf("FD_READ_BIT socket error code:%d\n", networkEvents.iErrorCode[FD_READ_BIT]);
continue;
}
}
if (networkEvents.lNetworkEvents & FD_CLOSE) {
if (networkEvents.iErrorCode[FD_CLOSE_BIT] == 0) {
printf("客户端正常退出\n");
}
else {
printf("客户端异常终止,错误码:%d\n", networkEvents.iErrorCode[FD_CLOSE_BIT]);
}
//清理下线的客户端,套接字,事件
//套接字
closesocket(eventSet.sockall[nIndex]);
eventSet.sockall[nIndex] = eventSet.sockall[eventSet.count - 1];
//事件
WSACloseEvent(eventSet.eventall[nIndex]);
eventSet.eventall[nIndex] = eventSet.eventall[eventSet.count - 1];
eventSet.count--;
}
}
}
//释放事件句柄
WSACloseEvent(hEvent);
closesocket(socketServer);
WSACleanup();
return 1;
}
2.扩充结构体 FD_ES的容量
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
typedef struct fd_es_set {
unsigned short count;
SOCKET sockall[WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT eventall[WSA_MAXIMUM_WAIT_EVENTS];
} FD_ES;
int main() {
WSADATA wsaData; // 创建一个 WSADATA 结构
// 初始化 Winsock 库,指定要使用的版本
int ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (ret != 0) {
printf("WSAStartup 失败,错误码: %d\n", ret);
return 0;
}
//校验版本
if (HIBYTE(wsaData.wVersion) != 2 || LOBYTE(wsaData.wVersion) != 2) {
printf("版本不符合");
WSACleanup();
return 0;
}
// 在这里进行网络编程操作
SOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketServer == INVALID_SOCKET) {
int errorCode = WSAGetLastError();
printf("socket创建失败,错误码:%u\n", errorCode);
closesocket(socketServer);
WSACleanup();
}
sockaddr_in si;
si.sin_family = AF_INET;
si.sin_addr.s_addr = inet_addr("127.0.0.1");
si.sin_port = htons(1234);
ret = bind(socketServer, (SOCKADDR*)&si, sizeof(si));
if (ret == SOCKET_ERROR) {
printf("bind绑定失败,错误码:%u\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
ret = listen(socketServer, SOMAXCONN);
if (ret == SOCKET_ERROR) {
printf("listen监听失败,错误码:%u\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
FD_ES eventSet[20];
memset(eventSet, 0, sizeof(eventSet));
//创建事件
WSAEVENT hEvent = WSACreateEvent();
if (hEvent == WSA_INVALID_EVENT) {
printf("WSACreateEvent errCode:%d\n", WSAGetLastError());
closesocket(socketServer);
WSACleanup();
return 0;
}
ret = WSAEventSelect(socketServer, hEvent, FD_ACCEPT);
if (ret == SOCKET_ERROR) {
printf("WSACreateEvent errCode:%d\n", WSAGetLastError());
//释放事件句柄
WSACloseEvent(hEvent);
closesocket(socketServer);
WSACleanup();
return 0;
}
eventSet[0].eventall[eventSet[0].count] = hEvent;
eventSet[0].sockall[eventSet[0].count] = socketServer;
eventSet[0].count++;
while (true) {
for (int i = 0; i < sizeof(eventSet) / sizeof(eventSet[0]); i++) {
if (eventSet[i].count == 0) {
continue;
}
DWORD dResult = WSAWaitForMultipleEvents(eventSet[i].count, eventSet[i].eventall, FALSE, 0, FALSE);
if (dResult == WSA_WAIT_FAILED) {
printf("WSAWaitForMultipleEvents ErrorCode:%d\n", WSAGetLastError());
continue;
}
if (dResult == WSA_WAIT_TIMEOUT) {
continue;
}
DWORD dIndex = dResult - WSA_WAIT_EVENT_0;
for (int nIndex = dIndex; nIndex < eventSet[i].count; nIndex++) {
//得到下标对应的事件
WSANETWORKEVENTS networkEvents;
ret = WSAEnumNetworkEvents(eventSet[i].sockall[nIndex], eventSet[i].eventall[nIndex], &networkEvents);
if (ret == SOCKET_ERROR) {
printf("WSAEnumNetworkEvents ErrorCode:%d\n", WSAGetLastError());
break;
}
if (networkEvents.lNetworkEvents & FD_ACCEPT) {
if (networkEvents.iErrorCode[FD_ACCEPT_BIT] == 0) {
//正常处理
SOCKET socketClient = accept(eventSet[i].sockall[nIndex], NULL, NULL);
if (socketClient == INVALID_SOCKET) {
continue;
}
//创建事件对象
WSAEVENT wsaClientEvent = WSACreateEvent();
if (wsaClientEvent == WSA_INVALID_EVENT) {
closesocket(socketClient);
continue;
}
//客户端socket投递给系统
ret = WSAEventSelect(socketClient, wsaClientEvent, FD_READ | FD_WRITE | FD_CLOSE);
if (ret == SOCKET_ERROR) {
closesocket(socketClient);
WSACloseEvent(wsaClientEvent);
continue;
}
for (int m = 0; m < 20; m++) {
if (eventSet[m].count < 64) {
//装进结构体
eventSet[m].sockall[eventSet[m].count] = socketClient;
eventSet[m].eventall[eventSet[m].count] = wsaClientEvent;
eventSet[m].count++;
break;
}
}
printf("accept event\n");
}
else {
continue;
}
}
if (networkEvents.lNetworkEvents & FD_WRITE) {
if (networkEvents.iErrorCode[FD_WRITE_BIT] == 0) {
char buffer[] = "connect success";
printf("FD_WRITE socket:%d\n", eventSet[i].sockall[nIndex]);
ret = send(eventSet[i].sockall[nIndex], buffer, strlen(buffer), 0);
if (ret == SOCKET_ERROR) {
printf("send failed, errCode:%d\n", WSAGetLastError());
continue;
}
printf("write event\n");
}
else {
printf("FD_WRITE_BIT socket error code:%d\n", networkEvents.iErrorCode[FD_WRITE_BIT]);
continue;
}
}
if (networkEvents.lNetworkEvents & FD_READ) {
if (networkEvents.iErrorCode[FD_READ_BIT] == 0) {
char buffer[1024] = { 0 };
printf("FD_READ socket:%d\n", eventSet[i].sockall[nIndex]);
ret = recv(eventSet[i].sockall[nIndex], buffer, sizeof(buffer), 0);
if (ret == SOCKET_ERROR) {
printf("recv failed, errCode:%d\n", WSAGetLastError());
continue;
}
printf("recv client data:%s\n", buffer);
const char send_buff[] = "hello, I'm is server";
ret = send(eventSet[i].sockall[nIndex], send_buff, sizeof(send_buff), 0);
if (ret == SOCKET_ERROR) {
printf("send失败,错误码:%u\n", WSAGetLastError());
}
}
else {
printf("FD_READ_BIT socket error code:%d\n", networkEvents.iErrorCode[FD_READ_BIT]);
continue;
}
}
if (networkEvents.lNetworkEvents & FD_CLOSE) {
if (networkEvents.iErrorCode[FD_CLOSE_BIT] == 0) {
printf("客户端正常退出\n");
}
else {
printf("客户端异常终止,错误码:%d\n", networkEvents.iErrorCode[FD_CLOSE_BIT]);
}
//清理下线的客户端,套接字,事件
//套接字
closesocket(eventSet[i].sockall[nIndex]);
eventSet[i].sockall[nIndex] = eventSet[i].sockall[eventSet[i].count - 1];
//事件
WSACloseEvent(eventSet[i].eventall[nIndex]);
eventSet[i].eventall[nIndex] = eventSet[i].eventall[eventSet[i].count - 1];
eventSet[i].count--;
}
}
}
}
//释放事件句柄
WSACloseEvent(hEvent);
closesocket(socketServer);
WSACleanup();
return 1;
}

浙公网安备 33010602011771号