select()函數


原型:

#include<sys/time.h>
#include<unistd.h>
int select(int maxfd, fd_set *rdset, fd_set *wrest, fd_set *exset, struct timeval *timeout);

參數:

  • maxfd:描述需要監視最大文件描述符+1
  • rdset:監視的可讀文件描述符的集合
  • wrset:監視的可寫文件描述符的集合
  • exset:監視的異常文件描述符的集合
  • struct timeval:描述一段時間長度,如果在這個時間內,需要監視的描述符沒有事件發生,返回0

返回值:

  • 超時返回0
  • 失敗返回-1
  • 成功返回大於0的整數,這個整數表示就緒描述符的數目
int FD_ZERO(fd_set *fdset):將指定的文件描述符集情況,在對文件描述符集合進行設置之前,必須對其進行初始化。如果不請空,由於在系統分配內存后,通常不做清空處理,所以結果時不可知的。
int FD_SET(int fd, fd_set *fdset);    用於在文件描述符集合中添加一個新的文件描述符
int FD_CLR(int fd, fd_set *fdset); 用於在文件描述符集合中刪除一個新的文件描述符
int FD_ISSET(int fd, fd_set *fdset); 用於測試指定的文件描述符是否在該集合中。

注意:fd_set通常是一個整數數組,其中每個整數中的每一位對應一個描述符(矢量),例如,使用一個32位整數,那么該數組的第一個元素對應於描述符0~31,第二個元素對應於描述符32~63,一次類推。

 

select 系統調用用途在於在一段指定的時間內,監聽用戶感興趣的文件描述符上可讀可寫和異常事件。

 

select使用范例:

當聲明了一個文件描述符集之后,必須用FD_ZERo將所有位置置0,然后再將我們所感興趣的描述符所對應的位置位:

  1. fd_set rset;
  2. int fd;
  3. FD_ZERO(&rset);
  4. FD_SET(fd,&rset);
  5. FD_SET(stdin,&rset);

然后調用select函數,阻塞等待文件描述符事件的到來如果超過設定的事件,則不再等待,繼續往下執行

select(fd+1,&rset,NULL,NULL,NULL);

select返回后,用FD_ISSET測試給定位是否置位。

if(FD_ISSET(fd, &rset))
{
…
    //do something
}

深入理解select模型:

理解selecr模型的關鍵是在於理解fd_set為了說明方便,取fd_set長度為1字節,fd_set的每一位bit可以對應一個文件描述符,則1字節長的fd_set最大可以對應8個fd。

  1. 執行fd_set set; FD_ZERO(&set); 則set用位表示為 0000,0000
  2. 若fd = 5,執行FD_SET(fd,&set);      后set變為0001,0000 (第5位置1)
  3. 若再加入fd = 2,fd = 1,則set變為0001,0011
  4. 執行select(6,&set,0,0,0)阻塞等待
  5. 若fd=1,fd=2上有事件發生,則select返回,此時set變為0000,0001。注意:沒有事件發生的fd=5被清空。

 

select模型特點:

  1. 可監控的文件描述符個數取決於sizeof(fd_set)的值。每個bit可以表示一個文件描述符。
  2. 將fd加入到select監控集的同事,還要再使用一個數據結構array保存放到select監控集中的fd,一是用於在select返回后,array作為元數據和fd_set進行FD_ISSET判斷。二是select返回后會把以前加入的但無事件發生的fd清空,則每次開始select前都要重新從array取得fd逐一加入人(FD_ZERO最先),掃描array的同時取得fd的最大值maxfd,用於select的第一個參數

可見select模型必須在select前循環加上fd,取maxfd,select 返回后在利用FD_ISSET判斷是否有事件發生。

 

select優勢:

用戶可以在一個線程內同時處理多個socket的IO請求,在網絡編程中,當涉及到多客戶訪問服務器的情況,除了使用fork多個進程來處理每個客戶的連接,還可以使用select來處理。

 

select缺點:

select本質是通過設置或者檢查存放fd標志位的數據結構來進行下一步處理,這樣帶來的缺點:

  • l  單個進程可監視的fd數量被限制,即能監聽端口的大小有限。一般來說這個數目和系統內存關系很大,具體數目可以cat /proc/sys/fs/file-max查看。
  • l  對socket進行掃描時是線性掃描,即采用輪詢的方法,效率較低,當套接字比較多的時候,每次select(0都要通過遍歷FD_SETSIZE個socket來完成調度,不管哪個socket是活躍的,都需要遍歷一遍。這就很浪費CPU事件,如果能給套接字注冊某個回調函數,當他們活躍時,自動完成相關操作,這就避免了輪詢,這正是epoll與kqueue做的
  • l  需要維護一個用來存放大量fd的數據結構,這樣會使得用戶空間和內核空間在傳遞該結構體時賦值開銷大。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM