• select模式学习(一)之:服务端


    #include "stdafx.h"

    //这个范例是个基于TCP协议的非阻塞模式下的SOCKET通信。
    //应该非常具有代表性了,分为服务器端和客户端。
    //非阻塞类型: Select模型

    ////////////////////////////////////////////
    //
    //   TCP Server  select非阻塞模式
    //   IP: 127.0.0.1
    //   PORT: 1207
    ////////////////////////////////////////////
    #pragma  comment(lib,"ws2_32.lib")

    #include <WinSock2.h>
    #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 ? ("阻塞模式"):("非阻塞模式"));
     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_ZERO(&fdRead);
      FD_ZERO(&fdWrite);
      FD_SET( sListen, &fdRead );
      //int minval = min(1,3,-1);
      //1.将待决的连接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 );
        }
       }
      //2.调用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;
     }

  • 相关阅读:
    GridControl 绑定非绑定列
    AutoMapper
    ABP-TaskEver 路线图
    Angular--页面间切换及传值的四种方法
    知行合一,止于至善
    AutoFac 依赖注入--问题集
    【入门】依赖注入(DI)-开始
    利用JAVA生成二维码
    sqlserver如何关闭死锁进程.
    Hadoop/HBase 配置snappy压缩
  • 原文地址:https://www.cnblogs.com/yuanxingdefan/p/2868973.html
Copyright © 2020-2023  润新知