1. 程式人生 > >TCP流式套接字的事件物件I/O管理WSAEventSelect程式設計

TCP流式套接字的事件物件I/O管理WSAEventSelect程式設計

/************************************************************************/ 
/* 事件物件I/O管理程式例項                                              */ 
/************************************************************************/ 
 
#include <WINSOCK2.H> 
#pragma comment(lib,"ws2_32"
#include <stdio.h> 
 
int main
() 

    printf("服務端程式\n"); 
    //------①載入---------- 
    WSADATA wsaData; 
    if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0
    { 
        printf("WSAStartup Failed,Error=【%d】\n",WSAGetLastError()); 
        return 1
    } 
    else 
        printf("①載入成功\n"); 
    //-------②建立流式套接字------------ 

    SOCKET s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
    if (s==INVALID_SOCKET) 
    { 
        printf("socket() Failed,Error=【%d】\n",WSAGetLastError()); 
        return 1
    } 
    else 
        printf("②已建立監聽套介面:【%d】\n",s); 
    //將套介面s置於”非阻塞模式“ 
    u_long u1=1
    ioctlsocket(s,FIONBIO,(u_long*)&u1); 
    //-----------③繫結本地地址--------------------- 

    struct sockaddr_in Sadd; 
    Sadd.sin_family=AF_INET; 
    Sadd.sin_port=htons(5555); 
    Sadd.sin_addr.S_un.S_addr=inet_addr("192.168.31.1"); 
    if (bind(s,(sockaddr*)&Sadd,sizeof(Sadd))==SOCKET_ERROR) 
    { 
        printf("bind() Failed,Error=【%d】\n",WSAGetLastError()); 
        return 1
    } 
    else 
        printf("③繫結成功,本地IP地址:【%s】,埠號:【%d】\n",inet_ntoa(Sadd.sin_addr),ntohs(Sadd.sin_port)); 
    //--------------④進入監聽狀態----------------- 
    if (listen(s,5)==SOCKET_ERROR) 
    { 
        printf("listen Failed,Error=【%d】\n",WSAGetLastError()); 
        return 1
    } 
    else 
        printf("④進入監聽狀態\n"); 
    //--------------⑤建立事件物件----------------- 
    WSAEVENT NewEvent=WSACreateEvent(); 
    if (NewEvent==WSA_INVALID_EVENT) 
    { 
        printf("WSACreateEvent() Failed,Error=【%d】\n",WSAGetLastError()); 
        return 1
    } 
    else 
        printf("⑤建立一個事件物件,返回的事件物件控制代碼NewEvent=%d\n",NewEvent); 
    //--------------⑥網路事件註冊------------ 
    int WESerror=WSAEventSelect(s,NewEvent,FD_ACCEPT|FD_CLOSE); 
    if (WESerror==INVALID_SOCKET) 
    { 
        printf("WSAEventSelect() Failed,Error=【%d】\n",WSAGetLastError()); 
        return -1
    } 
    else 
        printf("⑥套介面【%d】、事件物件【%d】和網路事件FD_ACCEPT|FD_CLOSE已關聯\n",s,NewEvent); 
    //-----------準備工作--------------- 
    int t=1
    WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS]; 
    SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS]; 
    int n=0
    eventArray[n]=NewEvent; 
    sockArray[n]=s; 
    n++; 
    //------------迴圈處理------------- 
    while (true
    { 
        //---------------⑦等待事件物件-------------- 
        int nIndex=WSAWaitForMultipleEvents(n,eventArray,FALSE,40000,FALSE); 
        printf("nIndex=%d\n",nIndex); 
        if (nIndex==WSA_WAIT_FAILED)//------7.1呼叫失敗--------- 
        { 
            printf("呼叫失敗\n"); 
            break
        } 
        else if (nIndex==WSA_WAIT_TIMEOUT)//-------7.2超時--------- 
        { 
            if (t<3
            { 
                printf("第【%d】次超時\n",t); 
                t++; 
                continue
            } 
            else 
            { 
                printf("第【%d】次超時,退出\n",t); 
                break
            } 
        } 
        //---------------7.3網路事件觸發事件物件控制代碼的工作狀態-------- 
        else 
        { 
            WSANETWORKEVENTS event;//該結構記錄網路事件和對應出錯程式碼 
            //---------⑧網路事件查詢----------- 
            WSAEnumNetworkEvents(sockArray[nIndex-WSA_WAIT_EVENT_0],NULL,&event); 
            WSAResetEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]); 
            if ((event.lNetworkEvents&FD_ACCEPT)!=0)       //------8.1處理FD_ACCEPT通知訊息 
            { 
                if (event.iErrorCode[FD_ACCEPT_BIT]==0
                { 
                    if (n>WSA_MAXIMUM_WAIT_EVENTS) 
                    { 
                        printf("Too many connections!\n"); 
                        break
                    } 
                    SOCKET sNew=accept(sockArray[nIndex-WSA_WAIT_EVENT_0],NULL,NULL); 
                    NewEvent=WSACreateEvent(); 
                    WSAEventSelect(sNew,NewEvent,FD_READ|FD_CLOSE); 
                    eventArray[n]=NewEvent; 
                    sockArray[n]=sNew; 
                    n++; 
                } 
            } 
            else if (event.lNetworkEvents&FD_READ)    //-------8.2處理FD_READ通知訊息 
            { 
                if (event.iErrorCode[FD_READ_BIT]==0
                { 
                    char buf[256]; 
                    memset(buf,0,256); 
                    int nRecv=recv(sockArray[nIndex-WSA_WAIT_EVENT_0],buf,sizeof(buf),0); 
                    if (nRecv>0
                    { 
                        printf("接收到客戶端【%d】資料:%s\n",sockArray[nIndex-WSA_WAIT_EVENT_0],buf); 
                    } 
                } 
            } 
            else if (event.lNetworkEvents&FD_CLOSE)  //---------8.3處理FD_CLOSE通知訊息 
            { 
                if (event.iErrorCode[FD_CLOSE_BIT]==0
                { 
                    closesocket(sockArray[nIndex-WSA_WAIT_EVENT_0]); 
                    WSACloseEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]); 
                    printf("套接字為【%d】的已關閉連線\n",sockArray[nIndex-WSA_WAIT_EVENT_0]); 
                } 
                else 
                { 
                    if (event.iErrorCode[FD_CLOSE_BIT]==10053
                    { 
                        closesocket(sockArray[nIndex-WSA_WAIT_EVENT_0]); 
                        WSACloseEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]); 
                        printf("客戶端【%d】非法關閉連線\n",sockArray[nIndex-WSA_WAIT_EVENT_0]); 
                    } 
                } 
                for (int j=nIndex-WSA_WAIT_EVENT_0;j<n-1;j++) 
                { 
                    sockArray[j]=sockArray[j+1]; 
                    eventArray[j]=eventArray[j+1]; 
                } 
                n--; 
            } 
        }// end 網路事件觸發 
    }//end while 
    printf("退出伺服器程式\n"); 
    closesocket(s); 
    WSACleanup(); 
    return 0