select函式

select函式

select()的機制中提供一fd_set的數據結構,實際上是一long類型的數組, 每一個數組元素都能與一打開的檔案句柄(不管是Socket句柄,還是其他 檔案或命名管道或設備句柄)建立聯繫,建立聯繫的工作由程式設計師完成, 當調用select()時,由核心根據IO狀態修改fd_set的內容,由此來通知執 行了select()的進程哪一Socket或檔案可讀或可寫。主要用於Socket通信當中!

基本信息

編程特點

一、如果一個發現I/O有輸入,讀取的過程中,另外一個也有了輸入,這時候不會產生任何反應.這就需要你的程式語句去用到select函式的時候才知道有數據輸入。

二、程式去select的時候,如果沒有數據輸入,程式會一直等待,直到有數據為止,也就是程式中無需循環和sleep。

Select在Socket編程中還是比較重要的,可是對於初學Socket的人來說都不太愛用Select寫程式,他們只是習慣寫諸如connect、accept、recv或recvfrom這樣的阻塞程式(所謂阻塞方式block,顧名思義,就是進程或是執行緒執行到這些函式時必須等待某個事件的發生,如果事件沒有發生,進程或執行緒就被阻塞,函式不能立即返回)。

可是使用Select就可以完成非阻塞(所謂非阻塞方式non-block,就是進程或執行緒執行此函式時不必非要等待事件的發生,一旦執行肯定返回,以返回值的不同來反映函式的執行情況,如果事件發生則與阻塞方式相同,若事件沒有發生,則返回一個代碼來告知事件未發生,而進程或執行緒繼續執行,所以效率較高)方式工作的程式,它能夠監視我們需要監視的檔案描述符的變化情況——讀寫或是異常。

返回值:準備就緒的描述符數,若逾時則返回0,若出錯則返回-1。

操作程式

下面具體解釋:

#include <sys/types.h>

#include <sys/times.h>

#include <sys/select.h>

int select(nfds, readfds, writefds, exceptfds, timeout)

int nfds;

fd_set *readfds, *writefds, *exceptfds;

struct timeval *timeout;

nfds:select監視的檔案句柄數,視進程中打開的檔案數而定,一般設為你要監視各檔案

中的最大檔案號加一。(註:nfds並非一定表示監視的檔案句柄數。官方文檔僅指出nfds is the highest-numbered file descriptor in any of the three sets, plus 1. (可在linux環境中通過man select命令查得))

readfds:select監視的可讀檔案句柄集合。

writefds: select監視的可寫檔案句柄集合。

exceptfds:select監視的異常檔案句柄集合。

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

當readfds或writefds中映象的檔案可讀或可寫或逾時,本次select()

就結束返回。程式設計師利用一組系統提供的宏在select()結束時便可判

斷哪一檔案可讀或可寫,對Socket編程特別有用的就是readfds。

宏解釋

幾行相關的宏解釋如下:

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, fd_set *fdset):檢查fdset聯繫的檔案句柄fd是否

可讀寫,當>0表示可讀寫。

(關於fd_set及相關宏的定義見/usr/include/sys/types.h)

socket讀寫

這樣,你的socket只需在有東西讀的時候才讀入,大致如下:

...

int sockfd;

fd_set fdR;

struct timeval timeout = ..;

...

for(;;) {

FD_ZERO(&fdR);

FD_SET(sockfd, &fdR);

switch (select(sockfd + 1, &fdR, NULL, NULL , &timeout)) {

case -1:

error handled by u;

break;

case 0:

timeout hanled by u;

break;

default:

if (FD_ISSET(sockfd, &fdR)) {

now u read or recv something;

/* if sockfd is father and server socket, u can now accept() */

}

}

}

所以一個FD_ISSET(sockfd)就相當通知了sockfd可讀。

至於struct timeval在此的功能,請man select。不同的timeval設定

使select()表現出逾時結束、無逾時阻塞和輪詢三種特性。由於

timeval可精確至百萬分之一秒,所以Windows的SetTimer()根本不算

什麼。你可以用select()做一個超級時鐘。

相關詞條

相關搜尋

熱門詞條

聯絡我們