linux中select的用法

来源:互联网 发布:rfid怎么写入数据 编辑:程序博客网 时间:2024/05/22 16:01

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)测试是哪个个文件的状态的变化。


测试程序,监视 标准输入,然后打印出来

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <errno.h>  
  3. #include <stdlib.h>   
  4. #include <sys/types.h>  
  5. #include <sys/time.h>  
  6. #include <unistd.h>   
  7.   
  8. int main()  
  9. {  
  10.         //int fds;   
  11.         int ret;  
  12.         char buf[100];  
  13.         int timecount;  
  14.         int maxfd;  
  15.           
  16.         fd_set rfds;//设置监听读集合  
  17.         struct timeval tv;//设置等待时间,0不等待,NULL一直等待。  
  18.           
  19.     
  20.         FD_ZERO(&rfds);//清空集合  
  21. /* 
  22. *   通常,一个进程启动时,都会打开 3 个文件:标准输入、标准输出和标准出错处理。这 
  23. *   3 个文件分别对应文件描述符为 0、1 和 2(也就是宏替换 STDIN_FILENO、STDOUT_FILENO 
  24. *   和 STDERR_FILENO,鼓励读者使用这些宏替换)。  
  25. */  
  26.         FD_SET(STDIN_FILENO, &rfds);//把标准输入句柄0加入到集合中  
  27.       
  28.   
  29.         maxfd = STDIN_FILENO + 1;  
  30.   
  31.         timecount = 0;  
  32.         while(1)  
  33.         {  
  34.             tv.tv_sec = 10;  
  35.             tv.tv_usec = 0;//设置等待时间  
  36.             ret = select(maxfd, &rfds, NULL, NULL, &tv);  
  37.             if(ret<0)  
  38.             {  
  39.                 printf("select error, process will eixt\n");  
  40.                 exit(0);  
  41.             }  
  42.             else if(FD_ISSET(STDIN_FILENO, &rfds))//测试是否有数据  
  43.             {  
  44.                     fgets(buf, 100, stdin);  
  45.                     if (!strncasecmp(buf, "quit", 4))   
  46.                     {  
  47.                         printf("exit test!\n");  
  48.                         break;  
  49.                     }  
  50.                     printf("You input is %s\n",buf);  
  51.                   
  52.             }  
  53.             else  
  54.             {  
  55.               
  56.                 timecount++;  
  57.                 printf("\ntime out: %d\n", timecount);  
  58.               
  59.             }  
  60.         }  
  61.         return 0;  
  62. }  

运行结果:

[cpp] view plaincopy
  1. root@lj:/work/tmp/select/keypad# gcc select_key.c -o select  
  2. root@lj:/work/tmp/select/keypad# ./select  
  3. hello  
  4. You input is hello  
  5.   
  6.   
  7. time out: 1  
  8.   
  9. time out: 2  
  10.   
  11. time out: 3  
0 0