select() 系統調用完整詳解select() 允許進程同時監控多個文件描述符 (I/O 設備),任一就緒即返回;無就緒時阻塞。
#include <sys/select.h>
#include <sys/time.h>
int select(int maxfd,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout);
maxfd:被監控的最大文件描述符值 **+1** (因描述符從 0 開始)。readfds:關注**讀就緒**的描述符集。writefds:關注**寫就緒**的描述符集。exceptfds:關注**異常條件**(如帶外數據)的描述符集。timeout:定時器。
NULL:無限阻塞,直到有就緒。tv_sec=0, tv_usec=0:非阻塞,立即返回 (輪詢)。timeval 結構struct timeval {
long tv_sec; // 秒
long tv_usec; // 微秒
};
errno 指示) 或被信號中斷 (EINTR)。關鍵:返回時,readfds/writefds/exceptfds 被**修改**,僅保留就緒的描述符,非就緒位被清零。
FD_ZERO(fd_set *set); // 清空集合
FD_SET(int fd, fd_set *set); // 添加 fd
FD_CLR(int fd, fd_set *set); // 移除 fd
FD_ISSET(int fd, fd_set *set); // 測試 fd 是否在集合中 (調用 select 後使用)
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd1, &fds);
FD_SET(fd2, &fds);
int maxfdp = (fd1 > fd2 ? fd1 : fd2) + 1;
struct timeval tv = {5, 0}; // 5 秒超時
int ret = select(maxfdp, &fds, NULL, NULL, &tv);
if (ret == -1) { perror("select"); exit(1); }
if (ret == 0) { printf("Timeout\n"); return 0; }
if (FD_ISSET(fd1, &fds)) { /* fd1 可讀 */ }
if (FD_ISSET(fd2, &fds)) { /* fd2 可讀 */ }
監控標準輸入 (STDIN_FILENO) 與一個文件 (test.txt):
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define TIMEOUT 5
#define BUF_LEN 1024
int main() {
fd_set readfds;
int fd_file = open("test.txt", O_RDONLY);
if (fd_file == -1) { perror("open"); return 1; }
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
FD_SET(fd_file, &readfds);
int maxfdp = (STDIN_FILENO > fd_file ? STDIN_FILENO : fd_file) + 1;
struct timeval tv = {TIMEOUT, 0};
int ret = select(maxfdp, &readfds, NULL, NULL, &tv);
if (ret == -1) { perror("select"); return 1; }
if (ret == 0) { printf("Timeout %d sec\n", TIMEOUT); return 0; }
char buf[BUF_LEN + 1];
if (FD_ISSET(STDIN_FILENO, &readfds)) {
int len = read(STDIN_FILENO, buf, BUF_LEN);
if (len > 0) { buf[len] = '\0'; printf("Stdin: %s", buf); }
}
if (FD_ISSET(fd_file, &readfds)) {
int len = read(fd_file, buf, BUF_LEN);
if (len > 0) { buf[len] = '\0'; printf("File: %s", buf); }
}
close(fd_file);
return 0;
}
GCC 編譯運行無誤。程序等待 5 秒,期間鍵盤輸入或文件可讀即處理。