Select函式用法

2021-08-26 09:44:04 字數 3691 閱讀 8867

select函式用於在非阻塞中,當乙個套接字或一組套接字有訊號時通知你,系統提供select函式來實現多路復用輸入/輸出模型,原型:       

#include

#include

int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);

引數maxfd是需要監視的最大的檔案描述符值+1;

rdset,wrset,exset分別對應於需要檢測的可讀檔案描述符的集合,可寫檔案描述符的集 合及異常檔案描述符的集合。

struct timeval結構用於描述一段時間長度,如果在這個時間內,需要監視的描述符沒有事件發生則函式返回,返回值為0。

fd_set(它比較重要所以先介紹一下)是一組檔案描述字(fd)的集合,它用一位來表示乙個fd(下面會仔細介紹),對於fd_set型別通過下面四個巨集來操作:

fd_zero(fd_set *fdset);將指定的檔案描述符集清空,在對檔案描述符集合進行設定前,必須對其進行初始化,如果不清空,由於在系統分配記憶體空間後,通常並不作清空處理,所以結果是不可知的。

fd_set(fd_set *fdset);用於在檔案描述符集合中增加乙個新的檔案描述符。 

fd_clr(fd_set *fdset);用於在檔案描述符集合中刪除乙個檔案描述符。 

fd_isset(int fd,fd_set *fdset);用於測試指定的檔案描述符是否在該集合中。

過去,乙個fd_set通常只能包含<32的fd(檔案描述字),因為fd_set其實只用了乙個32位向量來表示fd;現在,unix系統通常會在標頭檔案中定義常量fd_setsize,它是資料型別fd_set的描述字數量,其值通常是1024,這樣就能表示<1024的fd。根據fd_set的位向量實現,我們可以重新理解操作fd_set的四個巨集:

fd_set set;

fd_zero(&set);

fd_set(0, &set);

fd_clr(4, &set);

fd_isset(5, &set);

―――――――――――――――――――――――――――――――――――――――

注意fd的最大值必須2、select函式的介面比較簡單:

int select(int nfds, fd_set *readset, fd_set *writeset,fd_set* exceptset, struct tim *timeout);

功能:返回值:     

返回對應位仍然為1的fd的總數。

remarks:

三組fd_set均將某些fd位置0,只有那些可讀,可寫以及有異常條件待處理的fd位仍然為1。

舉個例子,比如recv(),   在沒有資料到來呼叫它的時候,你的執行緒將被阻塞,如果資料一直不來,你的執行緒就要阻塞很久.這樣顯然不好. 所以採用select來檢視套節字是否可讀(也就是是否有資料讀了)  

步驟如下——   

socket s;

.....

fd_set set;

while(1)

//do something here

}

理解select模型的關鍵在於理解fd_set,為說明方便,取fd_set長度為1位元組,fd_set中的每一bit可以對應乙個檔案描述符fd。則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,0011。注意:沒有事件發生的fd=5被清空。

基於上面的討論,可以輕鬆得出select模型的特點:

(1)可監控的檔案描述符個數取決與sizeof(fd_set)的值。我這邊服務 器上sizeof(fd_set)=512,每bit表示乙個檔案描述符,則我伺服器上支援的最大檔案描述符是512*8=4096。據說可調,另有說雖 然可調,但調整上限受於編譯核心時的變數值。本人對調整fd_set的大小不太感興趣,參考 /cppexplore/archive/2008/03/21/45061.html中的模型2(1)可以有效突破select可監控的檔案描述符上限。

(2)將fd加入select監控集的同時,還要再使用乙個資料結構array儲存放到select監控集中的fd,一是用於再select 返回後,array作為源資料和fd_set進行fd_isset判斷。二是select返回後會把以前加入的但並無事件發生的fd清空,則每次開始 select前都要重新從array取得fd逐一加入(fd_zero最先),掃瞄array的同時取得fd最大值maxfd,用於select的第乙個 引數。

(3)可見select模型必須在select前迴圈array(加fd,取maxfd),select返回後迴圈array(fd_isset判斷是否有時間發生)。

下面給乙個偽碼說明基本select模型的伺服器模型:

array[slect_len];

nsock=0;

array[nsock++]=listen_fd;(之前listen port已繫結並listen)

maxfd=listen_fd;

while

res=select(maxfd+1,&set,0,0,0);

if(fd_isset(listen_fd,&set))

foreach 下標1開始 (fd in array)

}

使用select函式的過程一般是:

先呼叫巨集fd_zero將指定的fd_set清零,然後呼叫巨集fd_set將需要測試的fd加入fd_set,接著呼叫函式select測試fd_set中的所有fd,最後用巨集fd_isset檢查某個fd在函式select呼叫後,相應位是否仍然為1。

以下是乙個測試單個檔案描述字可讀性的例子:

int isready(int fd)

下面還有乙個複雜一些的應用:

//這段**將指定測試socket的描述字的可讀可寫性,因為socket使用的也是fd

uint32 socketwait(tsocket *s,bool rd,bool wr,uint32 timems)

;

}

select函式用法

原型 int select intnfds fd set readfds fd set writefds fd set exceptfds const struct timeval timeout nfds 本引數忽略,僅起到相容作用。readfds 可選 指標,指向一組等待可讀性檢查的套介面。wr...

select函式的用法

select函式用於在非阻塞中,當乙個套接字或一組套接字有訊號時通知你,系統提供select函式來實現多路復用輸入 輸出模型,原型 int select int maxfd,fd set rdset,fd set wrset,fd set exset,struct timeval timeout 所...

fd set 用法 select函式相關

select 函式主要是建立在fd set型別的基礎上的。fd set 它比較重要所以先介紹一下 是一組檔案描述字 fd 的集合,它用一位來表示乙個fd 下面會仔細介紹 對於fd set型別通過下面四個巨集來操作 fd set set fd zero set fd set fd,set fd clr...