zoukankan      html  css  js  c++  java
  • 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;
     }

  • 相关阅读:
    Android 按键消息处理Android 按键消息处理
    objcopy
    SQLite多线程读写实践及常见问题总结
    android动画坐标定义
    Android动画效果translate、scale、alpha、rotate
    Android公共库(缓存 下拉ListView 下载管理Pro 静默安装 root运行 Java公共类)
    Flatten Binary Tree to Linked List
    Distinct Subsequences
    Populating Next Right Pointers in Each Node II
    Populating Next Right Pointers in Each Node
  • 原文地址:https://www.cnblogs.com/yuanxingdefan/p/2868973.html
Copyright © 2011-2022 走看看