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; }