WIN网络编程-select(I/O模型)

来源:互联网 发布:淘宝卖鲜活生产许可证 编辑:程序博客网 时间:2024/05/16 05:09

 

//////////////////////////////////////////////////////
// select.cpp文件

//select的优点是程序能够在单个线程内同时处理多个套接字连接,但是增加

//到fd_set结构的套接字是有限制的。winsock2.h定义为64,在包含winsock2.h

//之前重新定义它是可以的,但是最大不能超过1024,并且此值太大,影响服

//务器性能,因为select返回之前会检查这些集合中的套接字,并移除没有未

//决I/O操作的套接字。

//s为套接字

//FD_ZERO(*set)初始化set为空集合

//FD_CLR(s,*set)从set移除s

//FD_ISSET(s,*set)检查s是不是set的成员,如果是返回true

//FD_SET(s,*set)增加套接字到集合


#include "../common/initsock.h"
#include <stdio.h>

CInitSock theSock;  //初始化Winsock库
int main()
{
 USHORT nPort = 4567; //此服务器监听的端口号

 // 创建监听套节字
 SOCKET sListen = ::socket(AF_INET, SOCK_STREAM,IPPROTO_TCP); 
 sockaddr_in sin;
 sin.sin_family = AF_INET;
 sin.sin_port = htons(nPort);
 sin.sin_addr.S_un.S_addr = INADDR_ANY;
 // 绑定套节字到本地机器
 if(::bind(sListen,(sockaddr*)&sin, sizeof(sin)) ==SOCKET_ERROR)
 {
  printf(" Failed bind()/n");
  return -1;
 }
 // 进入监听模式
 ::listen(sListen, 5);

  // select模型处理过程
 // 1)初始化一个套节字集合fdSocket,添加监听套节字句柄到这个集合
 fd_setfdSocket;  // 所有可用套节字集合
 FD_ZERO(&fdSocket);
 FD_SET(sListen, &fdSocket);
 while(TRUE)
 {
  //2)将fdSocket集合的一个拷贝fdRead传递给select函数,
  //当有事件发生时,select函数移除fdRead集合中没有未决I/O操作的套节字句柄,然后返回。
  fd_set fdRead = fdSocket;
  int nRet = ::select(0,&fdRead, NULL, NULL, NULL);
  if(nRet >0)
  {
   //3)通过将原来fdSocket集合与select处理过的fdRead集合比较,
   //确定都有哪些套节字有未决I/O,并进一步处理这些I/O。
   for(int i=0;i<(int)fdSocket.fd_count; i++)
   {
    if(FD_ISSET(fdSocket.fd_array[i],&fdRead))
    {
     if(fdSocket.fd_array[i]== sListen)  //(1)监听套节字接收到新连接
     {
      if(fdSocket.fd_count< FD_SETSIZE)
      {
       sockaddr_inaddrRemote;
       intnAddrLen = sizeof(addrRemote);
       SOCKETsNew = ::accept(sListen, (SOCKADDR*)&addrRemote,&nAddrLen);
       FD_SET(sNew,&fdSocket);
       printf("接收到连接(%s)/n",::inet_ntoa(addrRemote.sin_addr));
      }
      else
      {
       printf("Too much connections! /n");
       continue;
      }
     }
     else
     {
      charszText[256];
      intnRecv = ::recv(fdSocket.fd_array[i], szText, strlen(szText),0);
      if(nRecv>0)      //(2)可读
      {
       szText[nRecv]= '/0';
       printf("接收到数据:%s/n", szText);
      }
      else        //(3)连接关闭、重启或者中断
      {
       ::closesocket(fdSocket.fd_array[i]);
       FD_CLR(fdSocket.fd_array[i],&fdSocket);
      }
     }
    }
   }
  }
  else
  {
   printf("Failed select() /n");
   break;
  }
 }
 return 0;

原创粉丝点击