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;
 }

posted on 2013-01-20 22:22  远行的帆 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/yuanxingdefan/archive/2013/01/20/2868973.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值