select() 函数原型:
/* 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);

nfds:表示需要监听的文件描述符的最大值 + 1;(即待测试的描述集的总个数)
那为什么需要 + 1呢?
因为待测试的描述集总是从0, 1, 2, ...开始的;所以,如果要检测的描述符为9, 10, 那么系统实际也要监测0, 1, 2, 3, 4, 5, 6, 7,8; 此时真正待测试的描述符的个数为11个, 也就是 MAX(9, 10) + 1;
有两点要注意:
1. 如果你要检测的文件描述符是9,10,但是你把select的第一个参数定为9, 实际上只检测0到8, 所以select不会感知到 9,10文件描述符的变化。
2. 如果你要检测的文件描述符是9,10,且你把select的第一个参数定为11, 实际上会检测0-10, 但是如果你不把描述如0 set到描述符中, 那么select也不会感知到0描述符的变化。
所以, select感知到描述符变化的必要条件是, 第一个参数要合理, 比如定义为fdMax+1, 且把需要检测的文件描述符set到描述集中。
可使用以下代码来测试下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/time.h>
#include<sys/types.h>
int main(void)
{
struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 500; // us
fd_set rdfds;
FD_ZERO(&rdfds);
FD_SET(STDIN_FILENO, &rdfds); // STDIN_FILENO是标准输入, 加入描述集
int ret= select(STDIN_FILENO + 1, &rdfds, NULL, NULL, &tv);
if (ret < 0) {
printf("selcet error, ret = %d\n", ret);
return -1;
} else if (ret == 0) {
printf("timeout \n");
}
printf("ret = %d \n", ret);
return 0;
}