I/O多路复用之poll

原文链接:https://www.cnblogs.com/zengzy/p/5115679.html

1、select的些许缺点

回忆一下 select接口 

int select(int nfdsfd_set *readfdsfd_set *writefdsfd_set *exceptfds, struct timeval *timeout);

select需要我们指定文件描述符的最大值,然后取[0,nfds)这个范围内的值查看是在集合readfds,writefds或execptfds中,也就是说这个范围内存在一些不是我们感兴趣的文件描述符,cpu做了一些无用功,poll对她进行了改进,下面就看看poll是怎么做的。

2、poll接口

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

跟select不同的是,poll不再告知内核一个范围,而是通过struct pollfd结构体数组精确的告知内核用户关心哪些文件描述符(流)。参数nfds指示结构体数组的大小。timeout表示程序员的忍耐度,有三种取值:

  • 0,poll函数不阻塞
  • 整数,阻塞timeout时间
  • 负数,无限阻塞

下面来看一下struct pollfd结构体,以及其中的事件有哪些取值,及其含义

struct pollfd {

  int fd; /* an open file file descriptor */
  short events; /* requested events */
  short revents; /* returned events */
};

  • fd属性表示一个打开的文件描述符
  • events属性是一个输入参数,通过bit mask的方式描述程序感兴趣的事件(读、写)
  • revents属性是一个传出参数,同样式通过bit mask的方式描述发生的事件,这个属性的值是由内核设置的。revents的值可能是events属性的值,也可能是POLLERR,POLLHUP,POLLNVAL的一个或多个,POLLERR,POLLHUP,POLLNVAL在events属性中是没有意义的。

events 和 revents能够设置的值都定义在<poll.h>头中,有以下几种可能

  • POLLIN ,读事件
  • POLLPRI,读事件,但表示紧急数据,例如tcp socket的带外数据
  • POLLRDNORM , 读事件,表示有普通数据可读     
  • POLLRDBAND , 读事件,表示有优先数据可读     
  • POLLOUT,写事件
  • POLLWRNORM , 写事件,表示有普通数据可写
  • POLLWRBAND , 写事件,表示有优先数据可写            
  • POLLRDHUP (since Linux 2.6.17),Stream socket的一端关闭了连接(注意是stream socket,我们知道还有raw socket,dgram socket),或者是写端关闭了连接,如果要使用这个事件,必须定义_GNU_SOURCE 宏。这个事件可以用来判断链路是否发生异常(当然更通用的方法是使用心跳机制)。要使用这个事件,得这样包含头文件:
      #define _GNU_SOURCE  
      #include <poll.h>
  • POLLERR,仅用于内核设置传出参数revents,表示设备发生错误
  • POLLHUP,仅用于内核设置传出参数revents,表示设备被挂起,如果poll监听的fd是socket,表示这个socket并没有在网络上建立连接,比如说只调用了socket()函数,但是没有进行connect。
  • POLLNVAL,仅用于内核设置传出参数revents,表示非法请求文件描述符fd没有打开

 

poll函数返回值,有三种可能

  • positive number,表示struct pollfd结构体数组中有多少个非0的revents,换句话说,就是这一次调用poll发生哪些事件。
  • 0,表示timeout到时,并且没有文件描述符准备好
  • -1,内部发生了错误,errno将会被设置

当poll返回值为-1时,表示poll出错,errno将被设置,errno的取值有4种可能

  • EFAULT ,参数struct pollfd结构体数组不在用户地址空间,比如传入的参数nfds比实际的数组要大。
  • EINTR ,被信号中断.
  • EINVAL , nfds 超出了RLIMIT_NOFILE值.
  • ENOMEM ,内核没有足够的内存装载struct pollfd结构体数组

3、poll与select参数对比

使用poll()和select()不一样,你不需要显式地请求异常情况报告。
POLLIN | POLLPRI等价于select()的读事件,POLLOUT |POLLWRBAND等价于select()的写事件。POLLIN等价于POLLRDNORM |POLLRDBAND,而POLLOUT则等价于POLLWRNORM。

4、poll原理

poll的功能和select的功能一样,只不过是参数稍微不同,poll的底层原理也和select差不多,就不多说了,I/O多路复用之select

写者:zengzy
出处: http://www.cnblogs.com/zengzy
标题有【转】字样的文章从别的地方转过来的,否则为个人学习笔记

分类: 网络编程 标签: I/O多路复用
<div id="blog_post_info"></div>
<div class="clear"></div>
<div id="post_next_prev">

<a href="https://www.cnblogs.com/zengzy/p/5113910.html" class="p_n_p_prefix">« </a> 上一篇:    <a href="https://www.cnblogs.com/zengzy/p/5113910.html" title="发布于 2016-01-08 22:25">I/O多路复用之select</a>
<br>
<a href="https://www.cnblogs.com/zengzy/p/5118336.html" class="p_n_p_prefix">» </a> 下一篇:    <a href="https://www.cnblogs.com/zengzy/p/5118336.html" title="发布于 2016-01-10 21:33">I/O多路复用之epoll</a>
上一篇:PHP 实例 - AJAX 投票


下一篇:I/O多路复用模型