海南最低工资标准2017:Socket通信(TCP)非阻塞模式-select模型 — Windows Live

来源:百度文库 编辑:中财网 时间:2024/04/28 16:21:52

Socket通信(TCP)非阻塞模式-select模型

 这个范例是个基于TCP协议的非阻塞模式下的SOCKET通信。应该非常具有代表性了,分为服务器端和客户端。非阻塞类型: 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        {
            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        {
            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        //检查是否为新的连接进入
        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            {
                for(nLoopi=0; 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;
}
////////////////////////////////////////////
//
//  TCP Client  非阻塞模式设定
//
////////////////////////////////////////////
#define CONNECT_IP        "127.0.0.1"
#define CONNECT_PORT      1207
#define DEFAULT_BUFF_LEN  256int _tmain(int argc, _TCHAR* argv[])
{
   WSAData       wsData;
   SOCKET        sServer;
   SOCKADDR_IN   addrServer;
   SOCKADDR_IN   addrLocal;
   char          sendBuff[DEFAULT_BUFF_LEN]={0};
   char          recvBuff[DEFAULT_BUFF_LEN]={0};
   int           nError;   printf(">>>>>TCP 客户端启动<<<<<<\n");
   WSAStartup( MAKEWORD(2,2), &wsData );   printf("-创建客户端用SOCKET\n");
   sServer = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
   if( sServer == INVALID_SOCKET )
   {
       printf("!!! socket failed: %d\n", WSAGetLastError());
       WSACleanup();
       return -1;
   }   addrServer.sin_family = AF_INET;
   addrServer.sin_addr.S_un.S_addr = inet_addr( CONNECT_IP );
   addrServer.sin_port = htons(CONNECT_PORT);
   printf("-设定服务器地址信息: %s:%d\n",inet_ntoa(addrServer.sin_addr), ntohs(addrServer.sin_port));
   //设定本地用地址和端口
   addrLocal.sin_family = AF_INET;
   addrLocal.sin_addr.S_un.S_addr = inet_addr( CONNECT_IP );
   addrLocal.sin_port = htons( 2701 );   printf("-绑定本地用地址和端口: %s:%d\n", inet_ntoa(addrLocal.sin_addr), ntohs(addrLocal.sin_port));
   nError = bind( sServer, (const sockaddr*)&addrLocal, sizeof(addrLocal) );
   if( nError == SOCKET_ERROR )
   {
       printf("!!! bind failed: %d\n", WSAGetLastError());
       WSACleanup();
       return -1;
   }
   printf("-连接指定服务器\n");
   nError = connect( sServer, (const sockaddr*)&addrServer, sizeof(addrServer) );
   if( nError == SOCKET_ERROR )
   {
       printf("!!! connect failed: %d\n", WSAGetLastError());
       closesocket( sServer );
       WSACleanup();
       return -1;
   }   ///////////////////////////////////
   //  客户端 SOCKET为非阻塞模式
   //
   ///////////////////////////////////
   DWORD nMode = 1;
   nError = ioctlsocket( sServer, FIONBIO, &nMode );
   if( nError == SOCKET_ERROR )
   {
       printf("!!! ioctlsocket failed: %d\n", WSAGetLastError());
       closesocket( sServer );
       WSACleanup();
       return -1;
   }
   printf("-SOCKET模式设定: %s\n", (nMode==0?"阻塞模式设定":"非阻塞模式设定"));
   printf("-开始准备送信受信\n");
   int nInputLen = 0;
   int nIndex    = 0;
   int nLeft     = 0;   fd_set  fdRead;
   fd_set  fdWrite;
   timeval tv={10,0};
   while(true)
   {       FD_ZERO( &fdRead );
       FD_ZERO( &fdWrite );
       FD_SET( sServer, &fdRead );
       FD_SET( sServer, &fdWrite );       nError = select( 0, &fdRead, &fdWrite, NULL, &tv );
       ;;;;;if( nError == 0 )
       {
           printf("!!! select time out\n");
           continue;
       }
       else if( nError < 0 )
       {
           printf("!!! select failed: %d\n", WSAGetLastError());
           break;
       }
     
 
       //发现SOCKET可读/可写
       if( FD_ISSET( sServer, &fdRead) )
       {
           memset( recvBuff, 0, sizeof(recvBuff) );
           nError = recv( sServer, recvBuff, sizeof(recvBuff)-1, 0 );
           ;;;;;if( nError == SOCKET_ERROR )
           {
               printf("!!! recv failed: %d\n", WSAGetLastError());
               break;
           }
           else if( nError == 0 )
           {
               printf("-Server Has Closed.\n");
               break;
           }
           recvBuff[nError] = '\0';
           printf("-Received: %s\n\n", recvBuff);
       }       if( FD_ISSET(sServer, &fdWrite) )
       {
           printf("Input Message You Want to Send( Quit ):\n");
           fflush( stdin );
           memset( sendBuff, 0, sizeof(sendBuff) );           fgets( sendBuff, sizeof(sendBuff)-1, stdin );
           nInputLen = strlen( sendBuff );
           sendBuff[nInputLen-1] = '\0';//去掉回车符 
           --nInputLen;
           nIndex = 0;
           nLeft  = nInputLen;           if(strcmp(sendBuff, "Quit")==0)
           {
               break;
           }           //将输入的数据发送过去
           while( nLeft > 0)
           {
               nError = send( sServer, &sendBuff[nIndex], nLeft, 0 );
               ;;;;if( nError == SOCKET_ERROR )
               {
                   printf("!!! send failed: %d\n",WSAGetLastError());
                   closesocket( sServer );
                   WSACleanup();
                   return -1;
               }
               else if( nError == 0 )
               {
                   printf("-Send OK.\n");
                   break;
               }
             
               nLeft  -= nError;
               nIndex += nError;
           }           printf("-Has send: %s\n",sendBuff);
       }   }//while(true)
   printf("-关闭SOCKET\n");
   closesocket(sServer);
   WSACleanup();   return 0;
}