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("-创建一个SOCKETn");
       sListen = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
       if(sListen==INVALID_SOCKET)
       {
               printf("!!! socket failed: %dn", 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:%dn", inet_ntoa(addrListen.sin_addr), ntohs(addrListen.sin_port));
       nRes = bind( sListen, (const sockaddr*)&addrListen, sizeof(addrListen) );
       if( nRes == SOCKET_ERROR )
       {
               printf("!!! bind failed: %dn", WSAGetLastError());
               closesocket( sListen );
               WSACleanup();
               return -1;
       }
       printf("-监听端口n");
       nRes = listen( sListen, MAX_LISTEN );
       if( nRes == SOCKET_ERROR )
       {
               printf("!!! listen failed: %dn", WSAGetLastError());
               closesocket( sListen );
               WSACleanup();
               return -1;
       }
       /
       //   非阻塞模式设定
       //
       /
       DWORD nMode = 1;
       nRes = ioctlsocket( sListen, FIONBIO, &nMode );
       if( nRes == SOCKET_ERROR )
       {
               printf("!!! ioctlsocket failed: %dn", WSAGetLastError());
               closesocket( sListen );
               WSACleanup();
               return -1;
       }
       printf("-设置服务器端模式: %sn", 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: %dn",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 secn",tv.tv_sec);
                       continue; //继续监听
               }
               else if( nRes < 0 )
               {
                       printf("!!! select failed: %dn", WSAGetLastError());
                       break;
               }

               //检查所有的可用SOCKET
               printf("-查找可用的SOCKETn");
               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] = '';
                                       printf("-Recvied: %sn", 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: %dn", 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:%dn", sClient, inet_ntoa(addrClient.sin_addr), ntohs(addrClient.sin_port));
                       }
                       else
                       {
                               printf("-服务器端连接数已满: %dn", sClient);
                               send( sClient, noresponseBuff, strlen(noresponseBuff), 0 );
                               closesocket( sClient );
                       }
               }//if( FD_ISSET( sListen, &fdRead) )
       }//while(true)
       printf("-关闭服务器端SOCKETn");
       closesocket( sListen );
       WSACleanup();
  return 0;
}


//
//   TCP Client   非阻塞模式设定
//

#define CONNECT_IP               "127.0.0.1"
#define CONNECT_PORT           1207
#define DEFAULT_BUFF_LEN   256
int _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("-创建客户端用SOCKETn");
     sServer = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
     if( sServer == INVALID_SOCKET )
     {
             printf("!!! socket failed: %dn", 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:%dn",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:%dn", inet_ntoa(addrLocal.sin_addr), ntohs(addrLocal.sin_port));
     nError = bind( sServer, (const sockaddr*)&addrLocal, sizeof(addrLocal) );
     if( nError == SOCKET_ERROR )
     {
             printf("!!! bind failed: %dn", WSAGetLastError());
             WSACleanup();
             return -1;
     }

     printf("-连接指定服务器n");
     nError = connect( sServer, (const sockaddr*)&addrServer, sizeof(addrServer) );
     if( nError == SOCKET_ERROR )
     {
             printf("!!! connect failed: %dn", WSAGetLastError());
             closesocket( sServer );
             WSACleanup();
             return -1;
     }
     ///
     //   客户端 SOCKET为非阻塞模式
     //
     ///
     DWORD nMode = 1;
     nError = ioctlsocket( sServer, FIONBIO, &nMode );
     if( nError == SOCKET_ERROR )
     {
             printf("!!! ioctlsocket failed: %dn", WSAGetLastError());
             closesocket( sServer );
             WSACleanup();
             return -1;
     }
     printf("-SOCKET模式设定: %sn", (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 outn");
                     continue;
             }
             else if( nError < 0 )
             {
                     printf("!!! select failed: %dn", 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: %dn", WSAGetLastError());
                             break;
                     }
                     else if( nError == 0 )
                     {
                             printf("-Server Has Closed.n");
                             break;
                     }
                     recvBuff[nError] = '';
                     printf("-Received: %snn", 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] = '';//去掉回车符 
                     --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: %dn",WSAGetLastError());
                                     closesocket( sServer );
                                     WSACleanup();
                                     return -1;
                             }
                             else if( nError == 0 )
                             {
                                     printf("-Send OK.n");
                                     break;
                             }
                         
                             nLeft   -= nError;
                             nIndex += nError;
                     }
                     printf("-Has send: %sn",sendBuff);
             }
     }//while(true)

     printf("-关闭SOCKETn");
     closesocket(sServer);
     WSACleanup();
     return 0;
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值