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需要遍歷判斷,檢驗等操作,所以看個從習慣選擇了。

 

發佈了43 篇原創文章 · 獲贊 1 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章