1. 程式人生 > >select函數總結

select函數總結

超時 esc print 特殊 sset 函數 建立 最大值 超時時間

阻塞方式block,就是進程或是線程執行到這些函數時必須等待某個事件的發生,如果事件沒有發生,進程或線程就被阻塞,函數不能立即返回。使用Select就可以完成非阻塞non-block,就是進程或線程執行此函數時不必非要等待事件的發生,一旦執行肯定返回,以返回值的不同來反映函數的執行情況,如果事件發生則與阻塞方式相同,若事件沒有發生則返回一個代碼來告知事件未發生,而進程或線程繼續執行,所以效率較高。select能夠監視我們需要監視的文件描述符的變化情況。

(一)首先說明兩個結構體:
1:struct fd_set一個存放文件描述符(file 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()函數原型:
1:int select(int nfds, fd_set *rdfds, fd_set *wtfds, fd_set *exfds, struct timeval *timeout)
2:ndfs:select中監視的文件句柄數,一般設為要監視的文件中的最大文件號加一。
3:rdfds:select()監視的可讀文件句柄集合,當rdfds映象的文件句柄狀態變成可讀時系統告訴select函數返回。
這個集合中有一個文件可讀,select就會返回一個大於0的值,表示有文件可讀,
如果沒有可讀的文件,則根據timeout參數再判斷是否超時,
若超出timeout的時間,select返回0,若發生錯誤返回負值,
可以傳入NULL值,表示不關心任何文件的讀變化;
4:wtfds: select()監視的可寫文件句柄集合,當wtfds映象的文件句柄狀態變成可寫時系統告訴select函數返回。
如果這個集合中有一個文件可寫,select就會返回一個大於0的值,表示有文件可寫,
如果沒有可寫的文件,則根據timeout參數再判斷是否超時,
若超出timeout的時間,select返回0,若發生錯誤返回負值,
可以傳入NULL值,表示不關心任何文件的寫變化。
5:exfds:select()監視的異常文件句柄集合,當exfds映象的文件句柄上有特殊情況發生時系統會告訴select函數返回。
6:timeout:select()的超時結束時間。
這個參數它使select處於三種狀態,
第一,若將NULL以形參傳入,即不傳入時間結構,就是將select置於阻塞狀態,
一定等到監視文件描述符集合中某個文件描述符發生變化為止;
第二,若將時間值設為0秒0毫秒,就變成一個純粹的非阻塞函數,不管文件描述符是否有變化,
都立刻返回繼續執行,文件無變化返回0,有變化返回一個正值;
第三,timeout的值大於0,這就是等待的超時時間,即select在timeout時間內阻塞,
超時時間之內有事件到來就返回了,否則在超時後不管怎樣一定返回,返回值同上述。

7:返回值:負值:select錯誤
0:等待超時,沒有可讀寫或錯誤的文件
正值:某些文件可讀可寫或出錯

(三)下面是一個有三個套接字句柄的例子

int sa, sb, sc;
sa = socket(...);
connect(sa,...);
sb = socket(...);
connect(sb,...);
sc = socket(...);
connect(sc,...);
FD_SET(sa, &rdfds);/* 分別把3個句柄加入讀監視集合裏去 */
FD_SET(sb, &rdfds);
FD_SET(sc, &rdfds);
int maxfd = 0;
if(sa > maxfd) maxfd = sa;/* 獲取3個句柄的最大值 */
if

(sb > maxfd) maxfd = sb;
if(sc > maxfd) maxfd = sc;
struct timeval tv;
tv.tv_sec = ... ;
tv.tv_usec = ...;
ret = select(maxfd + 1, &rdfds, NULL, NULL, &tv); /* 註意是最大值加1 */
if(ret < 0)
{
perror("select"); /* select函數出錯 */
}
else if(ret == 0)
{
printf("超時\n"); /* 在設定的tv時間內,socket的狀態沒有發生變化 */
}
else
{
printf("ret=%d\n", ret);
if(FD_ISSET(sa, &rdfds)) /* 先判斷一下sa這個被監視的句柄是否真的變成可讀的了 */
{
recv(...); /* 讀取socket句柄裏的數據 */
}
......
}

select函數總結