Winsock I/O 方法 select

select模型

        其使用select函數實現對I/O的管理。select函數可以判斷套接字上是否有數據,或者是否能夠向套接字上寫數據。設計這可函數的目的是,爲了防止套接字處於阻塞模式時,I/O調用過程處於阻塞模式;或者當套接字處於非阻塞模式時,產生WSAEWOULDBLOCK錯誤。如果不滿足實現規定的參數條件,那麼select函數在進行I/O操作時會阻塞。其定義如下:

  1. int select( 
  2.    int nfds, 
  3.    fd_set FAR* readfds, 
  4.    fd_set FAR* writefds, 
  5.    fd_set FAR* exceptfds, 
  6.    const struct timeval FAR* timeout 
  7. ); 
int select(
   int nfds,
   fd_set FAR* readfds,
   fd_set FAR* writefds,
   fd_set FAR* exceptfds,
   const struct timeval FAR* timeout
);

 

  • nfds:這個參數會被忽略。
  • readfds:其爲sd_set類型,其是一系列套接字的集合,用於檢查可讀性。這個集合要滿足下面條件之一:1)有數據可讀入  2)連接已經被關閉、重啓或終止  3)假如已經調用listen,且有一個連接處於擱置狀態,那麼accept調用成功。
  • wrtiefds:用於檢查可寫性。其套接字要滿足下面條件之一:1)有數據發出  2)如果正在對一個非阻塞連接調用進行處理,則連接就成功了。
  • exceptfds:用於帶外數據。其套機字要滿足下面條件之一:1)加入正在對一個非阻塞連接調用進行處理,連接嘗試機會失敗。  2)有00B數據可讀操作。
  • timeout:其一個指向timeval結構體的指針,用於表示select函數在調用返回前的等待時間,如果爲空指針({0,0}),表示無限期等待。不爲0,表示其中至少一個套接字滿足條件。
  • 返回值:如果select調用成功,會在fd_set結構中,返回被掛起的I/O操作的所有套接字句柄總量。超時,返回0。失敗,返回SOCKET_ERROR。

select返回後,會對每個fd_set結構體進行修改,會將那些不存在被掛起I/O操作的套接字刪除。也就是說,我們可以通過FD-ISSET宏來判斷等待的套接字是還處於宏中。

timeval結構體定義如下:

  1. struct timeval 
  2.    long tv_sec; 
  3.    long tv_usec; 
  4. }; 
struct timeval
{
   long tv_sec;
   long tv_usec;
};

 

  • tv_sec:以秒爲單位指定等待時間。
  • tv_usec:以毫秒爲單位指定等待時間。

在用select函數對套接字進行監聽前,需要將套接字分配給一個集合。對fd_set集合進行處理與檢查的宏:

  • FD_ZERO(*,set):將set集合初始化爲空。
  • FD_CLR(s,* set):從set中刪除套接字s.
  • FD_ISSET(s,* set):從集合set中檢查s是否在其中;是,就返回TRUE。
  • FD_SET(s,* set):將套接字s加入集合set中。
  • FD_SETSIZE:對fd_set結構中的最多套接字進行設置。因爲默認情況下最多能包含64個套接字。

下面是一個框架:

  1. SOCKET s; 
  2. fd_set fread; 
  3. int ret; 
  4. while(TRUE) 
  5.     FD_SERO(&fread); 
  6.     FD_SET(s,&fread); 
  7.     if((ret=select(0,&fread,NULL,NULL,NULL))==SOCKET_ERROR) 
  8.     { 
  9.       .... 
  10.     } 
  11.     if(ret>0) 
  12.     { 
  13.        if(FD_ISSET(s,&fread)) 
  14.        { 
  15.        } 
  16.     } 

 

例如,假定我們想知道是否可從一個套接字中安全地讀取數據,同時不會陷於無休止的“鎖

定”狀態,便可使用F D _ S E T宏,將自己的套接字分配給fd_read集合,再來調用select

。要想檢測自己的套接字是否仍屬fd_read集合的一部分,可使用FD_ISSET宏。採用下述步驟

,便可完成用select操作一個或多個套接字句柄的全過程:   
 1) 使用F D _ Z E R O宏,初始化自己感興趣的每一個 f d _ s e t 。   
 2) 使用F D _ S E T宏,將套接字句柄分配給自己感興趣的每個 f d _ s e t 。    
3)  調用s e l e c t函數,然後等待在指定的f d _ s e t集合中,I / O活動設置好一個或多個套接字句柄。 s e l e c t完成後,會返回在所有f d _ s e t集合中設置的套接字句柄總數,並對每個集合進行相應的更新。   
 4)  根據s e l e c t 的返回值,我們的應用程序便可判斷出哪些套接字存在着尚未完成(待決) 的I / O操作—具體的方法是使用F D _ I S S E T宏,對每個f d _ s e t集合進行檢查。   
 5)  知道了每個集合中“待決”的I / O操作之後,對I / O進行處理,然後返回步驟 1 )

,繼續進 行s e l e c t處理。

      s e l e c t返回後,它會修改每個 f d _ s e t結構,刪除那些不存在待決 I / O操作的套接字句柄。這正是我們在上述的步驟( 4 ) 中,爲何要使用F D _ I S S E T宏來判斷一個特定的套接字是否仍在集合中的原因。

 

 

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