zoukankan      html  css  js  c++  java
  • I/O多路复用之poll

    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

  • 相关阅读:
    30多条mysql数据库优化方法,千万级数据库记录查询轻松解决【转】
    安全快速修改Mysql数据库名的5种方法
    ASP.NET Web API 学习【转】
    前端学习必备知识
    为什么引用不了App_Code里的类(报“未能找到类型或命名空间名称”错误)
    【ASP.net】Equals 和 == 的区别
    ADO.NET完整的增、删、改、查
    面向对象--类库、委托、is和as运算符、泛型集合
    面向对象-构造函数和静态方法
    面向对象--多态、虚方法重写、抽象类、接口
  • 原文地址:https://www.cnblogs.com/zengzy/p/5115679.html
Copyright © 2011-2022 走看看