Winsock 网络编程 Socket模型之WSAEventSelect模型

来源:互联网 发布:淘宝电商线下实体店 编辑:程序博客网 时间:2024/04/19 11:34
前言:
讲一下套接字模式和套接字I/O模型的区别。先说明一下,只针对Winsock
套接字模式:阻塞套接字和非阻塞套接字。或是叫同步套接字和异步套接字。
套接字模型:描述如何对套接字的I/O行为进行管理
Winsock提供的I/O模式一共有五种:
Select模型,WSAAsyncSelect模型,WSAEventSelect模型,Overlapped模型(重叠IO),Completion模型(完成IO)

三、WSAEventSelect模型


创建监听用Socket

    // 载入socket DLL

    WSADATA   wdata;
    if (WSAStartup(MAKEWORD(2, 2), &wdata) != 0) {   
        
        // 失败
    }

    // 创建监听m_ListenSocket
    m_ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (INVALID_SOCKET == m_ListenSocket) {

        // 失败
    }

    // 启动受信线程

    m_ThreadId = 0; 
    m_Thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ReceiveThread, NULL, 0, &m_ThreadId );

      

受信线程

void ReceiveThread()
{

    //**************************************************
    // 创建Event对象
    //**************************************************

    // 处理结果
    BOOL bResult = TRUE;

    // Event对象数
    DWORD eventTotal = 0;

    // Event对象数组

    WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];

    // socket数组

    SOCKET socketArray[WSA_MAXIMUM_WAIT_EVENTS];

    // 把监听socket放入socket数组的首位置

    socketArray[eventTotal] = m_ListenSocket;

    // 创建监听socket用的Event对象、放入Event对象数组的首位置
    if ((eventArray[eventTotal] = ::WSACreateEvent()) == WSA_INVALID_EVENT) {
    
        // 失败

        bResult = FALSE;
    }

    if (bResult) {

        // 监听用event对象和监听socket绑定:绑定接受,关闭事件
        if (SOCKET_ERROR == ::WSAEventSelect(m_ListenSocket,
                                            eventArray[eventTotal],
                                            FD_ACCEPT|FD_CLOSE) ) {
        
            // 失败

            bResult = FALSE;
        } else {

            // Event对象数+1
            eventTotal++;

        }
    }

    //**************************************************
    // 监听socket绑定
    //**************************************************

    if (bResult) {

        // 绑定
        sockaddr_in ser_addr;
        ser_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");   
        ser_addr.sin_family=AF_INET;   
        ser_addr.sin_port=htons(50000); 
        if (SOCKET_ERROR == bind(m_ListenSocket, (LPSOCKADDR)&ser_addr, sizeof(ser_addr))) {

            // 失败
            bResult = FALSE;
        }
    }

    if (bResult) {
        
        // 监听开始
        if (SOCKET_ERROR == listen(m_ListenSocket, 5)) {

            // 失败

             bResult = FALSE;
        }
    }

    //**************************************************
    // 等待和处理网络事件
    //**************************************************

    if (bResult) {
    
        DWORD signaledIndex = 0;

        SOCKET signaledSocket = INVALID_SOCKET;
        WSAEVENT signaledEvent = WSA_INVALID_EVENT;

        //**************************************************
        // 等待网络事件
        //**************************************************

        while(TRUE) {

           //等待event对象被激发

            signaledIndex = ::WSAWaitForMultipleEvents(eventTotal,
                                                        eventArray,
                                                        FALSE,
                                                        INFINITE,
                                                        FALSE);
            if (WSA_WAIT_FAILED == signaledIndex) {
            
                // 失败
                break;
            }

            // 根据被激发的event对象的索引值,取得对应的socket以及event对象
            signaledSocket = socketArray[signaledIndex - WSA_WAIT_EVENT_0];
            signaledEvent = eventArray[signaledIndex - WSA_WAIT_EVENT_0];

            // 枚举网络中、在被激活的socket上、发生的网络事件
            WSANETWORKEVENTS netEvents;
            if (SOCKET_ERROR == ::WSAEnumNetworkEvents(signaledSocket, signaledEvent, &netEvents)){
                            
                // 失败
                break;
            }

            //******************************************************
            // FD_ACCEPT事件:网络中有客户端的连接请求
            //******************************************************

            if (netEvents.lNetworkEvents & FD_ACCEPT) {
            

                // 网络错误
                if (netEvents.iErrorCode[FD_ACCEPT_BIT] != 0) {
                    
                    // 失败
                    break;
                }

                sockaddr_in cli_addr;
                int addrlen = sizeof(cli_addr);

                // 连接
                if ((m_ClientSocket1 = accept(signaledSocket, (sockaddr *)&cli_addr, &addrlen))

                    == INVALID_SOCKET) {
                
                    // 失败
                    break;
                }

                // accept函数执行后,也会激活监听用socket的event对象,重置监听用socket的event对象
                WSAResetEvent(signaledEvent);

                // 判断是否超过最大可管理的socket数64
                if (eventTotal > WSA_MAXIMUM_WAIT_EVENTS) {

                    // 如果超过64个,关闭该连接,不再接收连接要求
                    closesocket(m_ClientSocket1);
                    break;
                }

                  // 把通信用socket放入socket数组

                socketArray[eventTotal] = m_ClientSocket1;

                // 为该通信用socket,创建event对象,并放入event对象管理数组
                if ((eventArray[eventTotal] = ::WSACreateEvent()) == WSA_INVALID_EVENT) {

                    // 失败                        
                    // 关闭该连接

                    closesocket(socketArray[eventTotal]);
                    break;
                }

                // event对象邦定:绑定读取,关闭事件
                if (SOCKET_ERROR == ::WSAEventSelect(socketArray[eventTotal],
                                                    eventArray[eventTotal],
                                                    FD_READ|FD_CLOSE) ) {
                
                    // 失败                        
                    // 关闭连接和event对象

                    closesocket(socketArray[eventTotal]);
                    WSACloseEvent(eventArray[eventTotal]);
                    break;
                }
                
                // Event对象数+1
                eventTotal++;
            }

            //**************************************************
            // FD_READ事件:网络中有可读入数据
            //**************************************************
            if (netEvents.lNetworkEvents & FD_READ) {

                // 网络错误
                if (netEvents.iErrorCode[FD_READ_BIT] != 0) {
                    
                    // 失败
                    break;
                }

                char recved[50];
                ZeroMemory(recved, 50);
                int recvedLen = 50;

                char info[50];
                ZeroMemory(info, 50);

                // 接收数据

                recvedLen = recv(signaledSocket, recved, recvedLen, 0);
                if (recvedLen == SOCKET_ERROR || recvedLen == 0) {

                    // 失败
                    break;
                }

            }

            //**************************************************
            // FD_CLOSE事件:断开连接
            //**************************************************
            if (netEvents.lNetworkEvents & FD_CLOSE) {  

                // 网络错误
                if (netEvents.iErrorCode[FD_CLOSE_BIT] != 0) {
                    
                    // 失败
                    break;
                }

               // 关闭连接

                closesocket(signaledSocket);
                WSACloseEvent(signaledEvent);

               // 把socket和event对象从管理数组中删除

                for (DWORD i = signaledIndex - WSA_WAIT_EVENT_0; i < eventTotal - 1; i++) {

                    socketArray[i] = socketArray[i + 1];
                    eventArray[i] = eventArray[i + 1];
                }

                // Event对象数-1
                eventTotal--;
            }
        }
    }
}


原创粉丝点击