I/O多路转接:先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已准备好进行I/O时,该函数才返回。在返回时,它告诉进程哪些描述符已准备好可以进行I/O。

poll、pselect和select这三个函数使我们能够执行I/O多路转接。

一、select函数

在所有依从POSIX的平台上,select函数使我们可以执行I/O多路转接。传向select的参数告诉内核:

  • 我们所关心的描述符。
  • 对于每个描述符我们所关心的状态。(是否读一个给定的描述符?是否想写一个给定的描述符?是否关心一个描述符异常状态?)
  • 愿意等待多长时间(可以永远等待,等待一个固定量时间或完全不等待)。

从select返回时,内核告诉我们:

  • 已准备好的描述符的数量。
  • 对于读、写或异常这三个状态中的每一个,哪些描述符已准备好。
#include <sys/select.h>
int select(int maxfdp1,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *tvptr);//返回值:准备就绪的描述符数,若超时则返回0,若出错则返回-1

先说明最后一个参数,它指定愿意等待的时间:

struct timeval{
long tv_sec; //seconds
long tv_usec;//and microseconds
}

有三种情况:

  • tvptr == NULL

永远等待。如果捕捉到一个信号则中断此无限期等待。当所指定的描述符中的一个已准备好或捕捉到一个信号则返回。如果捕捉到一个信号,则select返回-1,errno设置为EINTR

  • tvptr->tv_sec == 0 && tvptr->tv_usec == 0

完全不等待。测试所有指定的描述符并立即返回。

  • tvptr->tv_sec != 0 || tvptr->tv_usec != 0

等待指定的秒数和微妙数。当指定的描述符之一已准备好或当指定的时间值已经超过时立即返回。如果在超时时还没有一个描述符准备好,则返回值是0.与第一种情况一样,这种等待可被捕捉到的信号中断。

     中间三个参数readfds、writefds和exceptfds是指向描述符集的指针。这三个描述符集说明了我们关心的可读、可写或处于异常条件的各个描述符。每个描述符集存放在一个fd_set数据类型中。这种数据类型为每一可能的描述符保持了一位。
                                           
     对fd_set数据类型可以进行的处理是:分配一个这种类型的变量;将这种类型的一个变量值赋予同类型的另一个变量;或对于这种类型的变量使用下列四个函数中的一个。
#include <sys/select.>
int FD_ISSET(int fd,fd_set *fdset);//返回值:若fd在描述符集中则返回非0值,否则返回0
void FD_CLR(int fd,fd_set *fdset);
void FD_SET(int fd,fd_set *fdset);
void FD_ZERO(fd_set *fdset);
  • 调用FD_ZERO将一个指定的fd_set变量的所有位设置为0.
  • 调用FD_SET设置一个fd_set变量的指定位。
  • 调用FD_CLR则将一指定位清除。
  • 调用FD_ISSET测试一指定位是否设置。

select的中间三个参数(指向描述符集的指针)中的任意一个或全部都可以是空指针,这表示对相应状态并不关心。如果所有三个指针都是空指针,则select提供了较sleep更精确的计时器。
     select的第一个参数maxfdp1的意思是“最大描述符加1”。在三个描述符集中找出最大描述符值,然后加1,这就是第一个参数。也可以将第一个参数设置为FD_SETSIZE,这是<sys/select.h>中的一个常量,它说明了最大的描述符(经常是1024)。如果将第一个参数设置为我们关注的最大描述符编号值加1,内核就只需在此范围内寻找打开的位,而不必在三个描述符集中的数百位内搜索。

例如,若编写下列代码:
   fd_set readset,writeset;
FD_SERO(&readset);
FD_ZERO(&writeset);
FD_SET(0,&readset);
FD_SET(3,&readset);
FD_SET(1,&writeset);
FD_SET(2,&writeset);
select(4,readset,&writeset,NULL,NULL);

                               
     因为描述符编号从0开始,所以要在最大描述符编号值上加1。第一个参数实际上是要检查的描述符(从描述符0开始)。
select有三个可能的返回值:
  • 返回-1表示出错。出错是有可能的,例如在所指定的描述符都没有准备好时捕捉到一个信号。在此种情况下,将不修改其中任何描述符集。(即原先描述符值1的还是保持1,不变)
  • 返回0表示没有描述符准备好。若指定的描述符都没有准备好,而且指定的时间已经超时,则发生这种情况。此时,所有描述符集皆被清0
  • 正返回值表示已经准备好的描述符数,该值是三个描述符集中已经准备好的描述符数之和,所以如果同一描述符已准备好读和写,那么在返回值中将计2。在这种情况下,三个描述符集中仍旧打开的位对应于已准备好的描述符,其他没有准备好的清0。
     如果在一个描述符上碰到了文件结尾处,则select认为该描述符是可读的。然后调用read,它返回0,这是UNIX系统指示到达文件结尾处的方法。(很多人错误的认为,当到达文件结尾处时,select会指示一个异常状态)。
二、pselect函数
#include <sys/select.h>
int pselect(int maxfdp1,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timespec *tsptr,const sigset_t *sigmask);//返回值:准备就绪的描述符数,若超时则返回0,若出错则返回-1

除以下几点,pselect与select相同:

  • select的超时值用timeval结构指定,但pselect使用timespec,timespec结构以秒和纳秒表示超时值,而非秒和微妙。如果平台支持这样精细的粒度,那么timespec就提供了更精准的超时时间。
  • 对于pselect可使用一可选择的信号屏蔽字。若sigmask为空,那么在与信号有关的方面,pselect的运行状况和select相同。否则,sigmask指向一信号屏蔽字,在调用pselect时,以原子操作的方式安装该信号屏蔽字。在返回时恢复以前的信号屏蔽字。
三、poll函数
#include <poll.h>
int poll(struct pollfd fdarray[],nfds_t nfds,int timeout);

与select不同,poll不是为每个状态(可读性、可写性和异常状态)构造一个描述符集,而是构造一个pollfd结构数组,每个数组元素指定一个描述符编号以及对其关心的状态。

struct pollfd{
int fd; //file descriptor to check,or < 0 ignore
short events; //events of interest on fd
short revents; //events that occurred on fd
}

fdarray数组中的元素数由nfds说明。
     应将每个数组元素的events成员设置为下图。通过这些值告诉内核我们对该描述符关心的是什么。返回时,内核设置revents成员,以说明对于该描述符已经发生了什么事件。(注意:poll没有更改events成员,这与select不同,select修改其参数以指示哪一个描述符已准备好了)

     最后三行是由内核在返回时设置的。即使在events字段中没有指定这三个值,如果相应条件发生,则在revents中也返回它们。
     poll的最后一个参数说明我们愿意等待时间。有三种不同的情形:
  • timeout == -1 永远等待。当所指定的描述符中的一个已准备好,或捕捉到一个信号时则返回。如果捕捉到一个信号,则poll返回-1,errno设置为EINTR。
  • timeout == 0  不等待。
  • timeout > 0   等待timeout毫秒。当指定的描述符之一已准备好,或指定的时间值已超过时立即返回。如果已超时,但是还没有一个描述符准备好,则返回值是0。

UNIX环境高级编程——I/O多路转接(select、pselect和poll)的更多相关文章

  1. (十一) 一起学 Unix 环境高级编程 (APUE) 之 高级 IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  2. 《UNIX环境高级编程(第3版)》

    <UNIX环境高级编程(第3版)> 基本信息 原书名:Advanced Programming in the UNIX Environment (3rd Edition) (Addison ...

  3. (十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  4. multiple definition of `err_sys' 《UNIX环境高级编程》

    本文地址:http://www.cnblogs.com/yhLinux/p/4079930.html 问题描述: [点击此处直接看解决方案] 在练习<UNIX环境高级编程>APUE程序清单 ...

  5. unix环境高级编程基础知识之第二篇(3)

    看了unix环境高级编程第三章,把代码也都自己敲了一遍,另主要讲解了一些IO函数,read/write/fseek/fcntl:这里主要是c函数,比较容易,看多了就熟悉了.对fcntl函数讲解比较到位 ...

  6. (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  7. (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  8. (三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  9. (四) 一起学 Unix 环境高级编程(APUE) 之 系统数据文件和信息

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

随机推荐

  1. sql统计总和和各状态数

    统计状态数目 SELECT arch.dept_id ,dept.dept_name,COUNT(*) AS arch_sum, END) in_stock, END) on_loan, END) i ...

  2. SpringMVC 教程 - URI 链接

    原文链接:https://www.codemore.top/cates/Backend/post/2018-04-22/spring-mvc-uri-links 这一节主要讲的是Spring Fram ...

  3. P20 旅行助手,从未有过的至尊私人导游服务!

    旅行可以让人暂时抛掉生活中的琐事,工作上的压力,寻找内心的宁静.有的人是为了想多去见识不同的事物和人文风情,有的人是想去感受大自然的馈赠,看历史古迹感受古人智慧.歌德说过:人之所以爱旅行,不是为了抵达 ...

  4. Python学习札记-eval函数

    eval()函数 eval()官方文档里面给出来的功能解释是:将字符串string对象转化为有效的表达式参与求值运算返回计算结果 语法上:调用的是:eval(expression,globals=No ...

  5. monitoring with Prometheus

    Prometheus是一款开源的监控工具,支持k8s metrics的数据格式,同时也支持通过k8s api进行服务发现从而实现对自定义的metrics进行监控.下面通过一个示例来介绍如何将Prome ...

  6. Servlet生命周期与工作原理(转载)

    Servlet生命周期分为三个阶段: 1,初始化阶段  调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在 ...

  7. mybatis逆向工程,转载别人的,很清楚

    转载博客地址:http://www.cnblogs.com/selene/p/4650863.html

  8. Splay伸展树入门(单点操作,区间维护)附例题模板

    Pps:终于学会了伸展树的区间操作,做一个完整的总结,总结一下自己的伸展树的单点操作和区间维护,顺便给未来的自己总结复习用. splay是一种平衡树,[平均]操作复杂度O(nlogn).首先平衡树先是 ...

  9. 牛客网编程练习之PAT乙级(Basic Level):1032 选大王

    典型的约瑟夫环问题 AC代码: import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** * @ ...

  10. Android简易实战教程--第五十一话《使用Handler实现增加、减少、暂停计数》

    转载博客请注明出处:道龙的博客 之前,写过一篇使用异步任务AysncTask实现倒计时的小案例,喜欢的话可以参考博客:Android简易实战教程--第三十三话< AsyncTask异步倒计时&g ...