編程特點
一、如果一個發現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()做一個超級時鐘。