在C程序中,select函数定义于sys/select.h头文件中,是用于I/O多路复用的一个系统调用函数。该函数用于监视的文件描述符的变化情况–可读、可写或者异常。
/* According to POSIX.1-2001 */ #include <sys/select.h> /* According to earlier standards */ #include <sys/time.h> #include <sys/types.h> #include <unistd.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函数参数说明
nfds – 最大文件描述符+1
readfds - fd_set type 类型,只读的描述符集
writefds - fd_set type 类型,只写的描述符集
errorfds – fd_set type 类型,错误的描述符集
timeout – 超时等待时间
#include <sys/time.h> struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */ };
为了维护fd_set类型的参数,会使用下面四个宏:FD_SET(), FD_CLR(), FD_ZERO() 和 FD_ISSET()。
二、代码分析
#include <stdio.h> #include <stdlib.h> #include <sys/select.h> #include <unistd.h> #define TIMEOUT 10 // 设置超时时间秒数 #define MAX_LEN 4096 // 设置buffer最大字节数长度 int main(void) { fd_set readfds; struct timeval tv; int retval; FD_ZERO(&readfds); FD_SET(STDIN_FILENO, &readfds); tv.tv_sec = TIMEOUT; tv.tv_usec = 0; // 万事俱备,只等非阻塞 retval = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv); // 返回值为-1,出错。 if(retval < 0) { perror("select() error\n"); return 1; } // 返回值为正数,可读。 else if(retval) { // 测试一下,其实没必要。结果是肯定的。 if(FD_ISSET(STDIN_FILENO, &readfds)) { printf("Data is available now.\n"); char buf[MAX_LEN+1]; int len; len = read(STDIN_FILENO, buf, MAX_LEN); if(len == -1) { perror("read() error\n"); return 1; } else { buf[len] = '\0'; printf("read:\t%s\n", buf); } } } // 返回值为0,超时,还是无数据可读。 else { printf("No data within %d seconds.\n", TIMEOUT); } exit(EXIT_SUCCESS); }
三、运行结果
[root@localhost workspace]# gcc testselect.c -o testselect -Wall [root@localhost workspace]# ./testselect HELLO WORLD Data is available now. read: HELLO WORLD [root@localhost workspace]# ./testselect No data within 10 seconds.