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_READFD_WRITEFD_ACCEPTFD_CONNECT等。
    1. FD_ACCEPT:有客户端链接,与服务器socket绑定。
    2. FD_READ:有客户端发来消息,与客户端socket绑定,可多个属性并列用。
    3. FD_CLOSE:客户端下线,与客户端socket绑定,包含强制下线,正常下线。
    4. FD_WRITE:可以给客户端发送信息,与客户端socket绑定,会在accept后立即主动产生该信号,可以说明,客户端链接成功,即可随时发送信息。
    5. FD_CONNECT:客户端一方,给服务器绑定这个。
    6. 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;
}

 

 
posted @ 2023-09-29 13:12  TechNomad  阅读(297)  评论(0)    收藏  举报