IO模型(三)select --选择机制

   因为这个模型是后来才使用的,差一点就忘记了....这个模型是从UNIX里来的,是比较早的一种模型。上次总结的WSAEventSelect模型是微软将其进行改进后的版本。来看一下这个函数声明:

int select(
  intnfds,                             //忽略
  fd_set FAR*readfds,        //读操作
  fd_set FAR*writefds,       //写操作
  fd_set FAR*exceptfds,     //错误
  const struct timeval FAR*timeout  //等待的最大时间
);

   另外需要看一看几个操作函数:fd_set ,FD_SET,FD_ZERO,FD_ISSET

    1.fd_set:是一个结构体:

                   typedef struct fd_set {
                                                      u_int fd_count;                                   //记录个数
                                                      SOCKET fd_array[FD_SETSIZE];   //套接字数组
                                                        } fd_set;

    2.FD_SET:是宏操作看一下整的代码:

        #define FD_SET(fd, set) do { /
                                                        u_int __i; /
                                                        for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count; __i++) { /
                                                                if (((fd_set FAR *)(set))->fd_array[__i] == (fd)) { /
                                                                            break; /
                                                        } /
                                                      } /
                                                        if (__i == ((fd_set FAR *)(set))->fd_count) { /
                                                                if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) { /
                                                                                ((fd_set FAR *)(set))->fd_array[__i] = (fd); /
                                                                                ((fd_set FAR *)(set))->fd_count++; /
                                                                                   } /
                                                        } /
                                                        } while(0)

     这是Winsock2头文件里的定义,如果没有看过MFC仿真,看到这样的代码一定很头痛,函数操作还可以写成这样...

     其实它完成的功能就是将fd加载到记录set里。

    3.#define FD_ZERO(set) (((fd_set FAR *)(set))->fd_count=0)

    将记录set清零

    4.#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set FAR *)(set))

    检测fd是否在记录set里

好了现在开始例子:

//前三步省略...

//1.Winsock2.2初始化

//2.建立套接字 ServerSock

//3.bind并listen

//4.将建立好的套接字加入记录数组里

  fd_set fdSocket;

  //清零

  FD_ZERO(&fdSocket);

  //将建立好的套接字加入到记录

  FD_SET(ServerSock,&fdSocket);

  //开启线程处理通信事件

  HANDLE hThread = (HANDLE)_beginthreadex(0,0,ThreadProc,this,0,0);

//5.在线程里建立select模型

CSelectModelDlg* pDlg = (CSelectModelDlg*)pParam;//得到当前对话框的指针
 SOCKADDR_IN addrClient;
 int nLen = sizeof(SOCKADDR);
 while(1)
 {
  //保存fdSocket

  fd_set fdReadSocket = pDlg->fdSocket;

  //建立select模型,由于只关心FD_READ则只需处理第二个参数即可
  int nEvent = select(0,&fdReadSocket,NULL,NULL,NULL);
  if (nEvent > 0)
  {

   //当有事件到来时,遍历记录集
   for (int i = 0; i < pDlg->fdSocket.fd_count; i++)
   {

    //判断是否在记录集里

    if (FD_ISSET(pDlg->fdSocket.fd_array[i],(SOCKADDR*)&fdReadSocket))
    {

     //如果是Server端的套接字,则处理accept
     if (pDlg->ServerSocket == pDlg->fdSocket.fd_array[i])
     {
      if (pDlg->fdSocket.fd_count < FD_SETSIZE)
      {
       pDlg->ClientSocket = accept(pDlg->ServerSocket,(SOCKADDR*)&addrClient,&nLen);
       char* ip = inet_ntoa(addrClient.sin_addr);
       int nPort = ntohs(addrClient.sin_port);    

       //将返回的套接字加入到记录集里  
       FD_SET(pDlg->ClientSocket,&(pDlg->fdSocket)); //把ClientSocket加入到fdSocket
      }
     }
     else 
     {

      //如果不是Server端的套接字,则处理接收信息
      pDlg->ClientSocket = pDlg->fdSocket.fd_array[i];
      TCHAR szBuf[MAX_PATH] = {0};
      int nRecv = recv(pDlg->fdSocket.fd_array[i],(char*)szBuf,MAX_PATH*sizeof(TCHAR),0);
      if (nRecv >= 0)
      {
       szBuf[nRecv] = 0;
      }
      pDlg->SetDlgItemText(IDC_ED_RECV,szBuf);
     }
    }
   }
  }
 }

//

    无论代码实现还是逻辑方面我认为select比WSAEvenSelect实现起来要繁琐一些,建立模型后select需要遍历判断,检验等操作,所以看个从习惯选择了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值