poll和ppoll学习笔记

简介

poll/ppoll其实是同select/pselect类似的,用于同步多路I/O复用。poll/ppoll同select/pselect的最大区别在于poll/ppoll没有最大连接数限制,因为poll/ppoll使用的用于存储fd的集合是根据实际fd的数量动态分配的。此外,poll/ppoll监听的事件类型更加的丰富/细致些。

相关结构体定义

struct pollfd

/* Data structure describing a polling request.  */
struct pollfd {
    int fd;				/* File descriptor to poll.  */
    short int events;	/* Types of events poller cares about.  */
    short int revents;	/* Types of events that actually occurred.  */
};

结构成员说明
fd: 将要通过poll监听的fd;
events: 输入参数,通过poll监听fd的事件;
revents: 输出参数,poll监听获取到fd上实际发生的事件。
事件类型说明
POLLIN: IN/OUT。在events中设置,表示在fd上监听读事件;在revents中设置,表示fd上发生了读事件。
POLLPRI: IN/OUT。在events中设置,表示在fd上监听紧急数据读事件;在revents中设置,表示fd上发生了紧急数据读事件。紧急数据读事件包括:

  • TCP的带外数据;
  • 包模式下的伪终端主机在从机中出现了状态变化。

POLLOUT: IN/OUT。在events中设置,表示在fd上监听写事件;在revents中设置,表示fd上发生了写事件。
POLLRDHUP: IN/OUT。在events中设置,表示在fd上监听读挂起事件;在revents中设置,表示fd上发生了读挂起事件。读挂起事件是指在如TCP这样的流式socket上发生的连接对端已经关闭了连接,而本段还没关闭,使得该连接处于半连接状态。处于该状态下的fd是不允许写操作,而允许读操作。该事件是从linux内核版本2.6.17起才支持的。
POLLERR: OUT。只会出现在revents中,表示fd上发生了错误。
POLLHUP: OUT。连接对端处于挂起状态。
POLLNVAL: OUT。无效的请求数据,通常是由于fd是无效的造成。
POLLRDNORM: IN/OUT。需在编译时定义了宏 _XOPEN_SOURCE 时才可以用。作用同POLLIN相同。
POLLRDBAND: IN/OUT。需在编译时定义了宏 _XOPEN_SOURCE 时才可以用。在events中设置,表示在fd上监听具有优先级频带数据的读事件;在revents中设置,表示fd上发生了具有优先级频带数据的读事件。该事件通常Linux上是无用的。
POLLWRNORM: IN/OUT。需在编译时定义了宏 _XOPEN_SOURCE 时才可以用。作用同POLLOUT相同。
POLLWRBAND: IN/OUT。需在编译时定义了宏 _XOPEN_SOURCE 时才可以用。在events中设置,表示在fd上监听优先数据的可写入事件;在revents中设置,表示fd上发生了允许优先数据事件。

struct timespec

struct timespec {
    long    tv_sec;         /* seconds */
    long    tv_nsec;        /* nanoseconds */
};

相关函数介绍

poll

依赖头文件

#include <poll.h>

函数定义

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

功能和select相同,同时监听多个fd上的指定事件。直到一个或多个fd上有一个或多个事件发生时,或超时时才返回。
参数说明
fds: 指向struct pollfd结构数组的指针。数组的每个struct pollfd结构体对象标识一个fd及其相关事件。
nfds: 表示fds数组中的数组成员个数,即一次poll操作监听的fd的数量。
timeout: 超时时间,单位毫秒。
返回值说明
成功返回大于等于0,返回大于0表示三个fd集合中触发事件的fd的总个数,等于0表示等待超时;错误返回-1,错误码从errno中获取。
错误码说明
EFAULT: fds的内存地址错误,该地址不包含系统分配给进程的内存地址范围内。
EINTR: 在事件监听过程中被信号中断了。
EINVAL: nfds的数量超过了系统限制(RLIMIT_NOTFILE)。
ENOMEM: 内存不足错误,导致没有内存用于poll内部使用。

ppoll

依赖头文件

#define _GNU_SOURCE
#include <poll.h>

要使用ppoll,需地定义宏_GNU_SOURCE。

函数定义

int ppoll(struct pollfd *fds, nfds_t nfds,
          const struct timespec *timeout_ts, 
          const sigset_t *sigmask);

ppoll功能同poll相似。
参数说明
fds: 指向struct pollfd结构数组的指针。数组的每个struct pollfd结构体对象标识一个fd及其相关事件。
nfds: 表示fds数组中的数组成员个数,即一次poll操作监听的fd的数量。
timeout_ts: 超时时间,struct timespec结构形式,精度到纳秒,实际在底层实现时精度只到了毫秒。
sigmask: 指向一个设置了信号掩码信息的结构。如果不为NULL,则ppoll先将当前的信号掩码替换成sigmask指向的信号掩码,再执行poll,最后再替换会原来的信号掩码。
返回值说明
成功返回大于等于0,返回大于0表示三个fd集合中触发事件的fd的总个数,等于0表示等待超时;错误返回-1,错误码从errno中获取。
错误码说明
EFAULT: fds的内存地址错误,该地址不包含系统分配给进程的内存地址范围内。
EINTR: 在事件监听过程中被信号中断了。
EINVAL: nfds的数量超过了系统限制(RLIMIT_NOTFILE)。
ENOMEM: 内存不足错误,导致没有内存用于poll内部使用。

poll和ppoll比较

  1. poll的timeout使用的是int类型,单位为毫秒,所以精度为毫秒;ppoll的timeout使用的是struct timespec,精度为纳秒。
  2. ppoll带有sigmask参数,poll不带sigmask参数。

用例展示

poll

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <poll.h>

int
main(void)
{
    struct pollfd *fds;
    int retval;

    fds = (struct pollfd *)calloc(2, sizeof(struct pollfd));
    //stdin
    fds[0].fd = stdin;
    fds[0].events = POLLIN;
    fds[0].revents = 0;
    //stdout
    fds[1].fd = stdout;
    fds[1].events = POLLOUT;
    fds[1].revents = 0;

    retval = poll(rfds, 2, 5);

    if (retval == -1)
        perror("poll()");
    else if (retval) {
        if (fds[0].revents & POLLIN) {
            printf("Data is available now with stdin.\n");
        }
        if (fds[1].revents & POLLOUT) {
            printf("Data can write to stdout.\n");
        }
    } else
        printf("No data within five seconds.\n");
	free(fds);
    exit(EXIT_SUCCESS);
}

ppoll

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <poll.h>

int
main(void)
{
    struct pollfd *fds;
    int retval;
    struct timespec ts;

    fds = (struct pollfd *)calloc(2, sizeof(struct pollfd));
    //stdin
    fds[0].fd = stdin;
    fds[0].events = POLLIN;
    fds[0].revents = 0;
    //stdout
    fds[1].fd = stdout;
    fds[1].events = POLLOUT;
    fds[1].revents = 0;

    //timeout
    ts.tv_sec = 5;
    ts.tv_nsec = 0;

    retval = ppoll(rfds, 2, &ts, NULL);

    if (retval == -1)
        perror("ppoll()");
    else if (retval) {
        if (fds[0].revents & POLLIN) {
            printf("Data is available now with stdin.\n");
        }
        if (fds[1].revents & POLLOUT) {
            printf("Data can write to stdout.\n");
        }
    } else
        printf("No data within five seconds.\n");
	free(fds);
    exit(EXIT_SUCCESS);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值