select 非阻塞模式 服務器 代碼


//   TCP Server select非阻塞模式
//   IP: 127.0.0.1
//   PORT: 1207
#define LISTEN_IP    "127.0.0.1"
#define LISTEN_PORT 1207
#define DEFAULT_BUFF 256
#define MAX_LISTEN   2    //最多可同時連接的客戶端數量
int g_fd_ArrayC[MAX_LISTEN] = {0}; //處理所有的待決連接
int _tmain(int argc, _TCHAR* argv[])
{
    WSAData        wsData;
    SOCKET         sListen;
    SOCKET         sClient;
    SOCKADDR_IN    addrListen;
    SOCKADDR_IN    addrClient;
    int            addrClientLen = sizeof(addrClient);
    char           recvBuff[DEFAULT_BUFF] = {0};
    char           responseBuff[DEFAULT_BUFF] = {"Server Has Received"};
    char           noresponseBuff[DEFAULT_BUFF] = {"服務器端連接數已滿,無法連接"};
    int            nRes = 0;
    printf(">>>>>TCP 服務器端啓動<<<<<<\n");
    WSAStartup(MAKEWORD(2,2), &wsData);
    printf("-創建一個SOCKET\n");
    sListen = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    if(sListen==INVALID_SOCKET)
    {
        printf("!!! socket failed: %d\n", WSAGetLastError());
        WSACleanup();
        return -1;
    }
    printf("-設定服務器監聽端口\n");
    addrListen.sin_family = AF_INET;
    addrListen.sin_addr.S_un.S_addr = inet_addr( LISTEN_IP );
    addrListen.sin_port = htons( LISTEN_PORT );
    printf("-綁定SOCKET與指定監聽端口: %s:%d\n", inet_ntoa(addrListen.sin_addr), ntohs(addrListen.sin_port));
    nRes = bind( sListen, (const sockaddr*)&addrListen, sizeof(addrListen) );
    if( nRes == SOCKET_ERROR )
    {
        printf("!!! bind failed: %d\n", WSAGetLastError());
        closesocket( sListen );
        WSACleanup();
        return -1;
    }
    printf("-監聽端口\n");
    nRes = listen( sListen, MAX_LISTEN );
    if( nRes == SOCKET_ERROR )
    {
        printf("!!! listen failed: %d\n", WSAGetLastError());
        closesocket( sListen );
        WSACleanup();
        return -1;
    }
    /////////////////////////////
    // 非阻塞模式設定
    //
    /////////////////////////////
    DWORD nMode = 1;
    nRes = ioctlsocket( sListen, FIONBIO, &nMode );
    if( nRes == SOCKET_ERROR )
    {
        printf("!!! ioctlsocket failed: %d\n", WSAGetLastError());
        closesocket( sListen );
        WSACleanup();
        return -1;
    }
    printf("-設置服務器端模式: %s\n", nMode==0? "阻塞模式":"非阻塞模式");

    printf("-開始準備接受連接\n");
    fd_set fdRead;
    fd_set fdWrite;
    timeval tv={10,0};
    int     nLoopi = 0;
    int     nConnNum = 0;
    while(true)
    {
        printf("-select 開始\n");
        FD_ZERO(&fdRead, &fdWrite);
        FD_SET( sListen, &fdRead ); 
        //將待決的連接SOCKET放入fdRead集中進行select監聽

//每次進入循環都要沒空,重設
        for( nLoopi=0; nLoopi<MAX_LISTEN; ++nLoopi )
        {
            if( g_fd_ArrayC[nLoopi] !=0 )
            {
                printf("-LOOPI: 待決SOCKET: %d\n",g_fd_ArrayC[nLoopi] );
                FD_SET( g_fd_ArrayC[nLoopi], &fdRead );
            }
        }
        //調用select模式進行監聽
        nRes = select( 0, &fdRead, NULL, NULL, &tv );
        ;;;;;if( nRes == 0 )
        {
            printf("-!!! select timeout: %d sec\n",tv.tv_sec);
            continue; //繼續監聽
        }
        else if( nRes < 0 )
        {
            printf("!!! select failed: %d\n", WSAGetLastError());
            break;
        }

        //檢查所有的可用SOCKET
        printf("-查找可用的SOCKET\n");
        for( nLoopi=0; nLoopi<MAX_LISTEN; ++nLoopi )
        {
            if( FD_ISSET(g_fd_ArrayC[nLoopi], &fdRead) )
            {
                memset( recvBuff, 0 ,sizeof(recvBuff) );
                nRes = recv( g_fd_ArrayC[nLoopi], recvBuff, sizeof(recvBuff)-1, 0 );
                if( nRes <= 0 )
                {
                    printf("-Client Has Closed.\n");
                    closesocket( g_fd_ArrayC[nLoopi] );
                    //將已經關閉的SOCKET從FD集中刪除
                    FD_CLR( g_fd_ArrayC[nLoopi], &fdRead );
                    g_fd_ArrayC[nLoopi] = 0;
                    --nConnNum;
                }
                else
                {
                    recvBuff[nRes] = '\0';
                    printf("-Recvied: %s\n", recvBuff);
                    send( g_fd_ArrayC[nLoopi], responseBuff, strlen(responseBuff), 0 ); 
                }
            }
        }//for( nLoopi=0; nLoopi<MAX_LISTEN; ++nLoopi )

        //檢查是否爲新的連接進入
        if( FD_ISSET( sListen, &fdRead) )
        {
            printf("-發現一個新的客戶連接\n");
            sClient = accept( sListen, (sockaddr*)&addrClient, &addrClientLen );
            ;;;;;if( sClient == WSAEWOULDBLOCK )
            {
                printf("!!! 非阻塞模式設定 accept調用不正\n");
                continue;
            }
            else if( sClient == INVALID_SOCKET )
            {
                printf("!!! accept failed: %d\n", WSAGetLastError());
                continue;
            }
            //新的連接可以使用,查看待決處理隊列
            if( nConnNum<MAX_LISTEN )
            {
                for(nLoopi=0; nLoopi<MAX_LISTEN; ++nLoopi)
                {
                    if( g_fd_ArrayC[nLoopi] == 0 )
                    {//添加新的可用連接
                        g_fd_ArrayC[nLoopi] = sClient;
                        break;
                    }
                }
                ++nConnNum;
                printf("-新的客戶端信息:[%d] %s:%d\n", sClient, inet_ntoa(addrClient.sin_addr), ntohs(addrClient.sin_port));
            }
            else
            {
                printf("-服務器端連接數已滿: %d\n", sClient);
                send( sClient, noresponseBuff, strlen(noresponseBuff), 0 );
                closesocket( sClient );
            }
        }//if( FD_ISSET( sListen, &fdRead) )
    }//while(true)
    printf("-關閉服務器端SOCKET\n");
    closesocket( sListen );
    WSACleanup();
return 0;
}


原文轉自http://hi.baidu.com/duycllvljladfrr/item/9d0f02d4868d1ed4241f40a2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章