Linux 平臺(tái) select 操作
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set)
select() 操作用于程序監(jiān)控相應(yīng)的文件描述符(file descriptor,fd)是否準(zhǔn)備好,即能否進(jìn)行無(wú)阻塞地讀取操作。
文件描述符集(file descriptor set,fds)是函數(shù)最主要的參數(shù),它是一個(gè) fd_set 類型的結(jié)構(gòu)體,里面可以存儲(chǔ)最大 FD_SETSIZE(1024) 個(gè) fd。為了安全地操作 fds,系統(tǒng)提供了相應(yīng)的宏:
-
void FD_ZERO(fd_set *set)- 用于清空 fds 里存儲(chǔ)的 fd,一般在初始化時(shí)清空 fds 。 -
void FD_SET(int fd, fd_set *set)- 用于向 fds 里添加一個(gè) fd 。 -
void FD_CLR(int fd, fd_set *set)- 用于從 fds 里清除一個(gè) fd 。 -
int FD_ISSET(int fd, fd_set *set)- 用于判斷 fd 是否在 fds 里,一般在 select() 調(diào)用結(jié)束之后使用。
函數(shù)參數(shù)有三個(gè) fds:
| fds | 函數(shù)調(diào)用前 | 函數(shù)調(diào)用后 |
|---|---|---|
| readfds | 監(jiān)聽(tīng) readfds 里的 fd 是否有可讀的 | 可無(wú)阻塞讀的 fd |
| writefds | 監(jiān)聽(tīng) writefds 里的 fd 是否有可寫的 | 可無(wú)阻塞寫的 fd |
| exceptfds | 監(jiān)聽(tīng) exceptfds 里的 fd 是否有發(fā)送異常的(一般未使用) | 發(fā)生異常的 fd |
select() 函數(shù)內(nèi)部會(huì)修改 readfds, writefds 和 exceptfds 內(nèi)存儲(chǔ)的 fd,函數(shù)返回時(shí)這些 fds 內(nèi)存儲(chǔ)的是可以進(jìn)行相應(yīng)操作的 fd 。因此若希望在一個(gè) loop 里重復(fù)監(jiān)聽(tīng)某一個(gè) fd,需要每次調(diào)用 select() 之前重新設(shè)置 fds 。
函數(shù)參數(shù) nfds 是三個(gè) fds 里序號(hào)最大的 fd 的序號(hào)值 + 1 。
timeout 是一個(gè)struct timeval 的結(jié)構(gòu)體指針,它代表希望阻塞等待的時(shí)間。函數(shù)返回時(shí),Linux 平臺(tái)下的 timeout 會(huì)被重寫,用于存儲(chǔ)阻塞剩余未使用的時(shí)間,而其他平臺(tái)的實(shí)現(xiàn)一般不會(huì)這樣做。因此考慮到兼容性,一般認(rèn)為 select() 返回后,timeout 對(duì)象就沒(méi)用了,下次調(diào)用 select() 需要重新初始化 timeout 。
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
- 當(dāng)傳入的 timeout 里的字段值大于 0 ,select() 函數(shù)阻塞相應(yīng)的時(shí)間。當(dāng)一個(gè) fd 準(zhǔn)備好,被信號(hào)處理中斷,以及阻塞時(shí)間超時(shí)時(shí),函數(shù)返回。
- 當(dāng)傳入的 timeout 里的
tv_sec和tv_usec都為 0 時(shí),select() 函數(shù)立即返回,用于輪詢的場(chǎng)景。 - 當(dāng)傳入的 timeout 為 NULL 時(shí),select() 永久阻塞,直到有 fd 準(zhǔn)備好。
函數(shù)返回值可以為:
- EBADF - 錯(cuò)誤的 fd 。
- EINTR - 捕獲到信號(hào)。
- EINVAL -
nfds為負(fù)數(shù)或大于 RLIMIT_NOFILE 的限制,timeout的值不合理。 - ENOMEN - 函數(shù)內(nèi)部動(dòng)態(tài)分配內(nèi)存失敗。
一個(gè) demo 如下,簡(jiǎn)單地監(jiān)控標(biāo)準(zhǔn)輸入:
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.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);
}
無(wú)任何輸入場(chǎng)景:
tangjia@FA001334:~/Jackistang$ ./tmp
No data within five seconds.
輸入數(shù)據(jù)場(chǎng)景:
tangjia@FA001334:~/Jackistang$ ./tmp
123456798
Data is available now.
參考: