概況
select()的機制中提供一fd_set的
數據結構,其實是一long類型的
數組, 每個數組元素都能與一打開的
文件句柄(無論是Socket句柄,仍是其餘 文件或
命名管道或設備句柄)創建聯繫,創建聯繫的工做由
程序員完成, 當調用select()時,由
內核根據IO狀態修改fd_set的內容,由此來通知執 行了select()的進程哪一Socket或文件可讀。
阻塞式I/O編程有兩個特色:
1、若是一個發現I\O有輸入,讀取的過程當中,另一個也有了輸入,這時候不會產生任何反應.這就須要你的程序語句去用到select函數的時候才知道有數據輸入。
2、程序去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;
ndfs: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的聯繫。
可讀寫,當>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;
case 0:
timeout hanled by u;
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()作一個超級時鐘。