Windows网络编程之事件选择模型(三)
一、WSACreateEvent函数
WSACreateEvent
函数是Windows套接字API中的一部分,它用于创建套接字事件对象,以便在套接字操作上等待事件发生。这个函数通常与异步套接字操作一起使用,以允许应用程序异步地等待套接字事件的发生,而不需要阻塞线程。
函数原型:
1 | WSAEVENT WSAAPI WSACreateEvent( void ); |
参数:
无需传递任何参数。
返回值:
- 如果成功,函数返回一个
WSAEVENT
类型的句柄,代表创建的套接字事件对象。 - 如果失败,函数返回
WSA_INVALID_EVENT
,并且可以通过WSAGetLastError()
函数获取错误代码。
二、WSAEventSelect函数
WSAEventSelect
函数是Windows套接字编程中常用的函数,用于指定一个或多个事件,以便在套接字上等待这些事件的发生。这个函数通常与异步套接字一起使用,以允许应用程序在等待事件发生时不会阻塞线程。
函数原型:
1 2 3 4 5 | 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
函数结合使用,以便在异步套接字编程中有效地等待事件。
函数原型:
1 2 3 4 5 6 7 | 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函数
该函数发现指定套接字的网络事件的发生,清除内部网络事件记录,并重置事件对象。
函数原型:
1 2 3 4 5 | int WSAEnumNetworkEvents( SOCKET s, WSAEVENT hEventObject, LPWSANETWORKEVENTS lpNetworkEvents ); |
参数:
s
:要查询事件状态的套接字的描述符。hEventObject
:与套接字关联的事件对象的句柄。lpNetworkEvents
:一个指向WSANETWORKEVENTS
结构的指针,用于存储查询结果。
WSANETWORKEVENTS结构:
1 2 3 4 | 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源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | #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源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | #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有序优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | #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的容量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | #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的容量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | #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; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?