Select可以监控多个文件句柄,监控文件内容的变化,比如可读可写状态的改变,利用select可以实现非阻塞而不会让线程挂起,提高系统的运行效率。
比如可以同时 监控 键盘输入和鼠标输入,如果键盘有信号,可以去操作键盘,如果鼠标有信号,去处理鼠标事件,如果都没有信号,则可以不让线程挂起而继续向下执行。
1、 所需头文件:
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
2、函数原型
int select(int numfds,fd_set *readfds, fd_set *writefds,fd_set *exeptfds, struct timeval *timeout)
numfds:需要检查的号码最高的文件描述符加 1
readfds:由 select()监视的读文件描述符集合
writefds:由 select()监视的写文件描述符集合
exeptfds:由 select()监视的异常处理文件描述符集合
timeout
struct timeval {
long tv_sec; /* second */
long tv_unsec; /* and microseconds*/
}
NULL:永远等待,直到捕捉到信号或文件描述符已准备好为止
具体值:struct timeval 类型的指针,若等待为 timeout 时间还没有文件描符准备好,就立即返回
0:从不等待,测试所有指定的描述符并立即返回
函数返回值
成功:准备好的文件描述符
−1:出错
3.、select 文件描述符处理函数
FD_ZERO(fd_set *set) 清除一个文件描述符集
FD_SET(int fd,fd_set *set) 将一个文件描述符加入文件描述符集中
FD_CLR(int fd,fd_set *set) 将一个文件描述符从文件描述符集中清除
FD_ISSET(int fd,fd_set *set) 测试该集中的一个给定位是否有变化
使用步骤:
1、定义文件描述符
如:int int fds[2];
然后:fds[0] = open(....),打开文件。
2、定义要监视的集合
如:fd_set inset1,inset2;
初始化集合: FD_ZERO(&inset1);
把要监视的文件描述符添加进集合: FD_SET(fds[0],&inset1); 可以添加多个。
3、 设置监视的时间:
0:从不等待
NULL:永远等待
定义时间结构体:
struct timeval tv;
设置时间,如:
tv.tv_sec=2;tv.tv_usec=0;
注意当每次循环执行到select时,原来tv的值会被清零,必须重新设置
4、取出最大的那个文件
maxfd = fds[0]>fds[1] ? fds[0] : fds[1];
5、设置select(maxfd+1,&inset1,&inset2,NULL,&tv)
6、如果select返回大于0
可以用FD_ISSET(fds[0],&inset1)测试是哪个个文件的状态的变化。
测试程序,监视 标准输入,然后打印出来
- #include <stdio.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <unistd.h>
- int main()
- {
- //int fds;
- int ret;
- char buf[100];
- int timecount;
- int maxfd;
- fd_set rfds;//设置监听读集合
- struct timeval tv;//设置等待时间,0不等待,NULL一直等待。
- FD_ZERO(&rfds);//清空集合
- /*
- * 通常,一个进程启动时,都会打开 3 个文件:标准输入、标准输出和标准出错处理。这
- * 3 个文件分别对应文件描述符为 0、1 和 2(也就是宏替换 STDIN_FILENO、STDOUT_FILENO
- * 和 STDERR_FILENO,鼓励读者使用这些宏替换)。
- */
- FD_SET(STDIN_FILENO, &rfds);//把标准输入句柄0加入到集合中
- maxfd = STDIN_FILENO + 1;
- timecount = 0;
- while(1)
- {
- tv.tv_sec = 10;
- tv.tv_usec = 0;//设置等待时间
- ret = select(maxfd, &rfds, NULL, NULL, &tv);
- if(ret<0)
- {
- printf("select error, process will eixt\n");
- exit(0);
- }
- else if(FD_ISSET(STDIN_FILENO, &rfds))//测试是否有数据
- {
- fgets(buf, 100, stdin);
- if (!strncasecmp(buf, "quit", 4))
- {
- printf("exit test!\n");
- break;
- }
- printf("You input is %s\n",buf);
- }
- else
- {
- timecount++;
- printf("\ntime out: %d\n", timecount);
- }
- }
- return 0;
- }
运行结果:
- root@lj:/work/tmp/select/keypad# gcc select_key.c -o select
- root@lj:/work/tmp/select/keypad# ./select
- hello
- You input is hello
- time out: 1
- time out: 2
- time out: 3