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. web项目部署到阿里云服务器步骤

    http://www.cnblogs.com/qq3111901846/p/6178855.html http://blog.csdn.net/liona_koukou/article/details ...

  2. JSON.NET的Self referencing loop detected with type的原因以及解决办法

    模型中有循环引用是很常见的.例如,以下模型显示双向导航属性: : public class Category : { : public Category() : { : Products = new ...

  3. mysql catalog的名字

    def 算是一个一点卵用都没有的知识点 然后tmd各个版本不同 用这个语句查 SELECT * FROM information_schema.SCHEMATA where schema_name=' ...

  4. Django笔记--模型

    ORM是"对象-关系-映射"的简称,在Django当中,ORM就是模型类的管理器对象.操作顺序是先定义模型类,再定义模型类管理器,然后在模型类中实例化一个模型类管理器的对象,作为模 ...

  5. 韩顺平玩转Oracle视频资料整理

    .oracle10g 11g:g(grid)表示网格技术 以baidu搜索为准,现在想使用一个软件,但是此软件在离自己非常近的地方就存在了下载地址,但是与自己非常远的地方也同样存在一个下载地址,而搜索 ...

  6. Docker 编辑网络配置文件

    Docker 1.2.0 开始支持在运行中的容器里编辑 /etc/hosts, /etc/hostname 和 /etc/resolve.conf 文件. 但是这些修改是临时的,只在运行的容器中保留, ...

  7. C#基础拾遗系列之二:C#7.0新增功能点

    第一部分: C#是一种通用的,类型安全的,面向对象的编程语言.有如下特点: (1)面向对象:c# 是面向对象的范例的一个丰富实现, 它包括封装.继承和多态性.C#面向对象的行为包括: 统一的类型系统 ...

  8. 加解密、PKI与CA基础

    介绍 这门知识如果以前尝过的各位想必都知道:枯燥无比!因此在文中我会尽量讲的生动些,举一些例子,并试图以一个完整的例子来贯穿整个讲述过程.今年又恰逢莎翁逝世400周年,一方面也为了纪念这位伟大的作家. ...

  9. 安卓高级6 玩转AppBarLayout,更酷炫的顶部栏 Toolbar

    原文大神地址:http://www.jianshu.com/p/d159f0176576 上一篇文章[<CoordinateLayout的使用如此简单 >]上一篇文章<Coordin ...

  10. 20160218.CCPP体系详解(0028天)

    程序片段(01):加法.c 内容概要:字符串计算表达式 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <st ...