一、函數原型
DESCRIPTION
select() and pselect() allow a program to monitor multiple file
descriptors, waiting until one or more of the file descriptors become
"ready" for some class of I/O operation (e.g., input possible). A file
descriptor is considered ready if it is possible to perform a corre‐
sponding I/O operation (e.g., read(2) without blocking, or a suffi‐
ciently small write(2)).
int select(int nfds, //需要檢查的號碼最高的文件描述符加 1
fd_set *readfds, //由 select()監視的讀文件描述符集合
fd_set *writefds, //由 select()監視的寫文件描述符集合
fd_set *exceptfds, //由 select()監視的異常處理文件描述符集合
struct timeval *timeout); //超時設定
selecth和pselect允許程序監控一個或多個文件的狀態變化,以下分別介紹每個參數的意義。
二、struct fd_set
在linux下任何設備、管道、FIFO等都是文件形式,這裏也包括socket。所以struct fd_set實際上就是一個文件描述符的集合。
在實現上通過32bits實現對不同fd的狀態記錄。
/* We will use a 32-bit bitsets to represent the set of descriptors. How
* many uint32_t's do we need to span all descriptors?
*/
struct fd_set_s
{
uint32_t arr[__SELECT_NUINT32];
};
接下來要介紹幾個接口函數:
- FD_ZERO(fd_set *);清空集合
- FD_SET(int, fd_set *);將一個給定的文件描述符加入集合之中
- FD_CLR(int, fd_set*);將一個給定的文件描述符從集合中刪除
- FD_ISSET(int ,fd_set* );檢查集合中指定的文件描述符是否可以讀寫。
三、struct timeval
struct timeval 是一個常用的結構,用來代表時間值,有兩個成員,一個是秒數,另一個是毫秒。
/* struct timeval represents time as seconds plus microseconds */
struct timeval
{
time_t tv_sec; /* Seconds */
long tv_usec; /* Microseconds */
};
四、舉個例子
EXAMPLE:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
else if (retval)
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) will be true. */
else
printf("No data within five seconds.\n");
exit(EXIT_SUCCESS);
}
這個例子是通過終端> man select拿到的,就以這個例子來做講解。
retval = select(1, &rfds, NULL, NULL, &tv);
- int nfds:
是一個整數值,是指集合中所有文件描述符的範圍,即所有文件描述符的最大值加1。
- fd_set* readfds:
是指向fd_set結構的指針,這個集合中應該包括可讀文件描述符,是否可以從這些文件中讀取數據了。
如果這個集合中有一個文件可讀,select就會返回一個大於0的值,表示有文件可讀;
如果沒有可讀的文件,則根據timeout參數再判斷是否超時,若超出timeout的時間,select返回0;
如果發生錯誤,則返回負值。
如果傳入的readfds的值是NULL值,則表示不關心任何文件的讀變化。
- d_set* writefds:
是指向fd_set結構的指針,這個集合中應該包括可寫文件描述符,是否可以向這些文件中寫入數據了。
如果這個集合中有一個文件可寫,select就會返回一個大於0的值,表示有文件可寫;
如果沒有可寫的文件,則根據timeout參數再判斷是否超時,若超出timeout的時間,select返回0;
如果發生錯誤,則返回負值。
如果傳入的writefds的值是NULL值,則表示不關心任何文件的讀變化。
- fd_set * errorfds:
用來監視文件錯誤異常,和以上的兩個指針是相同用法,這裏不再贅述。
- struct timeval* timeout:
是設置select的超時時間
NULL,即不傳入時間結構,就是將select置於阻塞狀態,一定等到監視文件描述符集合中某個文件描述符發生變化爲止;
0秒0毫秒,(selcet變爲非阻塞函數),不管文件描述符是否有變化,都立刻返回繼續執行;
大於0,這就是等待的超時時間,即select在timeout時間內阻塞,超時時間之內有事件到來就返回了。