1. 程式人生 > >select詳解及其限制

select詳解及其限制

前言:筆者前幾天參加面試,被問到select函式的限制,然後感覺一頭霧水,回來之後趕緊查找了資料彌補知識短板,也意識到以後使用一些系統呼叫應該多想些為什麼,結合現實去思考實際中會遇到的問題。

下面是對selecth函式的一些總結:

select是網路IO模型中的IO複用(在之前筆者還以為select屬於非同步io),瞭解select之前大家可以先了解下IO模型,下面兩篇文章講的很不錯:

網路IO模型:

IO - 同步,非同步,阻塞,非阻塞 (亡羊補牢篇) - 智障大師 的專欄 - 部落格頻道 - CSDN.NET

網路IO之阻塞、非阻塞、同步、非同步總結 - Anker's Blog - 部落格園

I/O複用之select:

int select( int nfds,                            

const struct timeval  *timeout

);

一、引數:

1、int nfds:select監視的檔案控制代碼數,視程序中開啟的檔案數而定,一般設為你要監視各檔案中的最大檔案號加一。

2、readfdsselect監視的可讀檔案控制代碼集合。

當rdfds映象的檔案控制代碼狀態變成可讀時系統告訴select函式返回。這個集合中有一個檔案可讀,select就會返回一個大於0的值,表示有檔案讀,如果沒有可讀的檔案,則根據timeout引數再判斷是否超時,若超出timeou

t的時間,select返回0,若發生錯誤返回負值,可以傳入NULL值,表示不關心任何檔案的讀變化

3、writefds: select監視的可寫檔案控制代碼集合。

當wtfds映象的檔案控制代碼狀態變成可寫時系統告訴select函式返回。如果這個集合中有一個檔案可寫,select就會返回一個大於0的值,表示有檔案可寫,如果沒有可寫的檔案,則根據timeout引數再判斷是否超時,若超出timeout的時間,select返回0,若發生錯誤返回負值,可以傳入NULL值,表示不關心任何檔案的寫變化。

4、exceptfdsselect監視的異常檔案控制代碼集合。

當exfds映象的檔案控制代碼上有特殊情況發生時系統會告訴select函式返回。

5、timeout:本次select()的超時結束時間。(見/usr/sys/select.h,可精確至百萬分之一秒!)

這個引數有以下三種可能:

1、引數設為空指標:永遠等待下去:僅在有一個檔案描述符準備好I/O時才返回。

2、等待一段固定時間:在有一個描述符準備好I/O時才返回,但是不超過該引數所指向timeout結構中指定的秒數和微秒數

3、根本不等待;檢查描述符後立即返回,這稱為輪詢(polling)。為此,該引數必須指向timeout結構,而且其中的定時器值必須是0.

這裡涉及到兩個結構體:

1、struct fd_set:存放檔案描述符(flie descriptor)的集合,即檔案控制代碼的集合,實際上是long型別的陣列,每一個數組元素都能與一開啟的檔案控制代碼(不管是socket控制代碼,還是其他檔案或命名管道或裝置控制代碼)建立聯絡,建立聯絡的工作由程式設計師完成。如下:

FD_ZERO(fd_set *fdset):清空fdset與所有檔案控制代碼的聯絡。
FD_SET(int fd, fd_set *fdset):建立檔案控制代碼fd與fdset的聯絡。
FD_CLR(int fd, fd_set *fdset):清除檔案控制代碼fd與fdset的聯絡。
FD_ISSET(int fd, fdset *fdset):檢查fdset聯絡的檔案控制代碼fd是否可讀寫,>0表示可讀寫。

2、struct timeval用來表示時間值,有兩個成員,一個是秒數tv_sec,另一個是毫秒tv_usec.

二、返回值:

負值:select錯誤0:等待超時,沒有可讀寫或錯誤的檔案正值:某些檔案可讀可寫或出錯

三、控制代碼數限制

select 最不能忍受的是一個程序所開啟的FD是有一定限制的,由FD_SETSIZE設定,預設值是1024。對於那些需要支援的上萬連線數目的IM伺服器來說顯然太少了。這時候你一是可以選擇修改這個巨集然後重新編譯核心,不過資料也同時指出這樣會帶來網路效率下降。(不過 epoll則沒有這個限制,它所支援的FD上限是最大可以開啟檔案的數目,這個數字一般遠大於2048,舉個例子,在1GB記憶體的機器上大約是10萬左右,具體數目可以cat /proc/sys/fs/file-max檢視,一般來說這個數目和系統記憶體關係很大。)