表头文件
#i nclude<sys/time.h>
#i nclude<sys/types.h>
#i nclude<unistd.h>
定义函数
int select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout);
函数说明
select()用来等待文件描述词状态的改变。参数n代表最大的文件描述词加1,参数readfds、writefds 和exceptfds 称为描述词组,是用来回传该描述词的读,写或例外的状况。底下的宏提供了处理这三种描述词组的方式:
FD_CLR(inr fd,fd_set* set);用来清除描述词组set中相关fd 的位
FD_ISSET(int fd,fd_set *set);用来测试描述词组set中相关fd 的位是否为真
FD_SET(int fd,fd_set*set);用来设置描述词组set中相关fd的位
FD_ZERO(fd_set *set); 用来清除描述词组set的全部位
参数
timeout为结构timeval,用来设置select()的等待时间,其结构定义如下
struct timeval
{
time_t tv_sec;
time_t tv_usec;
};
返回值
如果参数timeout设为NULL则表示select()没有timeout。
错误代码
执行成功则返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间,当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。
EBADF 文件描述词为无效的或该文件已关闭
EINTR 此调用被信号所中断
EINVAL 参数n 为负值。
ENOMEM 核心内存不足
范例
常见的程序片段:fs_set readset;
FD_ZERO(&readset);
FD_SET(fd,&readset);
select(fd+1,&readset,NULL,NULL,NULL);
if(FD_ISSET(fd,readset){……}


在Linux中,我们可以使用 select 函数实现I/O端口的复用,传递给 select 函数的参数会告诉内核:
      • 我们所关心的文件描述符
      • 对每个描述符,我们所关心的状态。(我们是要想从一个文件描述符中读或者写,还是关注一个描述符中是否出现异常)
      • 我们要等待多长时间。(我们可以等待无限长的时间,等待固定的一段时间,或者根本就不等待)
    从 select 函数返回后,内核告诉我们一下信息:
      • 对我们的要求已经做好准备的描述符的个数
      • 对于三种条件哪些描述符已经做好准备.(读,写,异常)
    有了这些返回信息,我们可以调用合适的I/O函数(通常是 read 或 write),并且这些函数不会再阻塞.
?
1
2
<span style="font-family: 'courier new', courier;">    #include <sys/select.h>   
    int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout)</span>

    
    返回:做好准备的文件描述符的个数,超时为0,错误为 -1.
    
    首先我们先看一下最后一个参数。它指明我们要等待的时间:
?
1
2
3
4
5
<span style="font-family: 'courier new', courier;">   struct timeval
    {      
        long tv_sec;  /* 秒 */
        long tv_usec; /* 微秒 */   
    }</span>

    
    有三种情况:
    timeout == NULL   等待无限长的时间。等待可以被一个信号中断。当有一个描述符做好准备或者是捕获到一个信号时函数会返回。如果捕获到一个信号, select 函数将返回 -1,并将变量 erro 设为 EINTR。
    timeout->tv_sec == 0 && timeout->tv_usec == 0 不等待,直接返回。加入描述符集的描述符都会被测试,并且返回满足要求的描述符的个数。这种方法通过轮询,无阻塞地获得了多个文件描述符状态。
    timeout->tv_sec !=0 ||timeout->tv_usec != 0  等待指定的时间。当有描述符符合条件或者超过超时时间的话,函数返回。在超时时间即将用完但又没有描述符合条件的话,返回 0。对于第一种情况,等待也会被信号所中断。
    
    中间的三个参数 readset, writset, exceptset, 指向描述符集。这些参数指明了我们关心哪些描述符,和需要满足什么条件(可写,可读,异常)。一个文件描述集保存在 fd_set 类型中。fd_set 类型变量每一位代表了一个描述符。
    
    对于 fd_set 类型的变量我们所能做的就是声明一个变量,为变量赋一个同种类型变量的值,或者使用以下几个宏来控制它:
?
1
2
3
4
5
<span style="font-family: 'courier new', courier;"> #include <sys/select.h>   
int FD_ZERO(int fd, fd_set *fdset);   
int FD_CLR(int fd, fd_set *fdset);   
int FD_SET(int fd, fd_set *fd_set);   
int FD_ISSET(int fd, fd_set *fdset);</span>

    FD_ZERO宏将一个 fd_set 类型变量的所有位都设为 0,使用FD_SET 将变量的某个位置位。清除某个位时可以使用 FD_CLR,我们可以使用 FD_SET 来测试某个位是否被置位。
    当声明了一个文件描述符集后,必须用FD_ZERO将所有位置零。之后将我们所感兴趣的描述符所对应的位置位,操作如下:
?
1
2
3
4
5
<span style="font-family: 'courier new', courier;">fd_set rset;   
int fd;   
FD_ZERO(&rset);   
FD_SET(fd, &rset);   
FD_SET(stdin, &rset);</span>

     
    select 返回后,用FD_ISSET测试给定位是否置位:
?
1
2
<span style="font-family: 'courier new', courier;">if(FD_ISSET(fd, &rset)   
{ ... }</span>


下面给出一个程序的实例:

程序执行后等待用户输入。如果用户输入程序就会把它打印到屏幕上。如果用户在3秒钟未输入任何字符,程序就打印“Time out!”.

       本程序实现了一个文件描述符的非阻塞I/O。

#include <sys/time.h>#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int main(){int keyboard;int ret=0;char c;fd_set readfd;struct timeval timeout;if((keyboard=open(“/dev/tty”,O_RDONLY|O_NONBLOCK))<0) /*打开标准输入(键盘)的文件描述符*/exit(1);/如果失败则退出程序*/while(1){timeout.tv_sec=3;/*设置等待时间为3秒*/timeout.usec=0;FD_ZERO(&readfd);/*初始化描述符集*/FD_SET(keyboard,&readfd);/*把标准输入(键盘)加入到描述符集中*/ret=select(keyboard+1,&readfd,NULL,NULL,&timeout);if(ret==0)/*如果超时打印下面的语句*/printf(“Time out!\n”);if(FD_ISSET(keyboard,&readfd))/*如果描述符集readfd的keyboard位被设置*/{read(keyboard,&c,1);/*从键盘上读如一个字符*/if(c==’\n’)continue;printf(“You input is %c\n”,c);if(c==’q’)break;}}}

UNIX中的Select函数相关推荐

  1. UNIX中的Poll函数

    poll函数和select函数非常相似,但是函数接口不一样. int poll(struct pollfd fdarray[], nfds_t nfds, int timeout); int sele ...

  2. UNIX网络编程——select函数的并发限制和 poll 函数应用举例

    http://blog.csdn.net/chenxun_2010/article/details/50489577 一.用select实现的并发服务器,能达到的并发数,受两方面限制 1.一个进程能打 ...

  3. linux select函数返回值,socket中的select函数使用

    socket select()函数用于定时检查以创建的socket句柄的状态,以确定设定的socket句柄当前是否可写或有数据可读. select函数提供了一种方法,使得程序在操作socket时(如r ...

  4. 在windows下使用python中的select函数报错‘[WinError 10038] 在一个非套接字上尝试了一个操

    注意:Python的select方法在Windows和Linux环境下的表现是不一样的,Windows下它只支持socket对象,不支持文件描述符(file descriptions),而Linux两 ...

  5. R进阶(1) --dplyr中的Select函数

    大神Hadley Wickham的dplyr包更新到了1.0.0版 .今天探究一下里面的神函数select. 首先检查你是否安装了最新版本的dplyr版本 packageVersion("d ...

  6. Python网络编程中的select 和 poll I/O复用的简单使用

    From: http://www.cnblogs.com/coser/archive/2012/01/06/2315216.html 首先列一下,sellect.poll.epoll三者的区别  se ...

  7. 从select函数谈及系统调用原理

    目录 系统调用流程 select函数 在glibc-2.28中查找select函数 在linux内核linux-4.20.1中查找select 参考: linux的select机制在socket编程中 ...

  8. c++中的fork函数_fork函数

    复刻(fork,又译作派生.分支)是UNIX或类UNIX中的分叉函数,fork函数将运行着的程序分为2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程.这两个进程中的线程继续 ...

  9. SOCKET编程中,select()函数的作用

    SOCKET编程中,select()函数的作用Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect.accep ...

最新文章

  1. eclipse 快捷键汇总
  2. python作者叫什么-Python18:什么是字典
  3. Winform中通过代码给PanelControl添加子控件并进行定位
  4. 手把手教你webpack3(3)入口(多入口)entry
  5. 【CV】语义分割:最简单的代码实现!
  6. thymeleaf语法介绍
  7. 织梦直接写php标签,怎么在自己的php页面中使用dedecms标签
  8. 144显示器只有60_你知道显示器60Hz和144Hz的刷新率差别有多大吗?你没有用过吗?...
  9. 从UnitedStack OS 1.0 Preview试用申请问卷调查学习OpenStack
  10. 机器学习中生成模型和判别模型
  11. windows安装卸载mysql
  12. 《编码-隐匿在计算机软硬背后的语言》第七章我们的十个数字
  13. 第H题 输入N求N的阶乘的10进制表示的长度
  14. 618秒杀抢不到?用Python完成毫秒级抢单,助你秒杀淘宝大单
  15. JS 用window.open()函数详解
  16. 发动机冒黑烟_发动机冒黑烟的原因和解决方法
  17. 卡巴斯基7.0反病毒一年激活码免费领取(官方活动,现已停止)
  18. 最新课表 | 谱尼学院十一月培训课程重磅来袭!
  19. springboot 集成 fastdfs
  20. 输入一串字符(不要超过80个,以回车结束输入),统计其中英文字母、空格或回车、数字字符和其他字符的个数。

热门文章

  1. PowerMockito的简单的介绍
  2. 敏捷软件开发--计划
  3. SQL效率低下原因主要有
  4. Oracle 触发器(上)
  5. INFO ipc.Client:Retrying connect to server 9000
  6. 存储----DAS、SAN、NAS
  7. linux下IO口模拟I2C的一些总结
  8. EMOS 1.5安装和配置
  9. html字体颜色代码表
  10. 知识点030-邮件告诉自己备份是否成功