poll

Posted ronny-blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poll相关的知识,希望对你有一定的参考价值。

  poll, ppoll - wait for some event on a file descriptor

  man page:  http://man7.org/linux/man-pages/man2/poll.2.html

 

  poll 是一种多路复用的IO机制。使用 poll 可以监听多个文件描述符,一但某个文件描述符就绪(一般是读就绪或者写就绪),能够通知程序进行响应的读写操作。

  poll 本质是一种同步IO,因为需要在读写事件就绪后自己负责读写,也就是说这个读写过程是阻塞的,而异步IO则无需自己负责读写,异步IO的实现会负责把数据从内核拷贝到用户空间。

#include <poll.h>

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

/**
 * 由于 poll 是监听多个文件描述符,所以 fds 传递的是数组地址
 * nfds 指定监听的文件描述符个数
 * timeout 超时时间,单位是 milliseconds
 * 
 * 因为 poll 是同步 IO,那么 poll 必然是带阻塞的,带阻塞的函数,必然要设置超时时间,防止死等却等不到的情况。
 */

 

struct pollfd {
    int   fd;         /* file descriptor */
    short events;     /* requested events */
    short revents;    /* returned events */
};

/**
 * fd     : 是要监听的文件描述符
 * events : 要监听的事件
 * revents: 实际发生的事件
 */

  pollfd 没有最大数量的限制,但是数量过大后性能会下降。当然,随着pollfd的个数增加,poll 函数返回后,用户继续遍历 poll 数组也会更加耗时。

       /* 常用参数说明 */
       POLLIN There is data to read.

       POLLPRI
              There is some exceptional condition on the file descriptor.
              Possibilities include:

              *  There is out-of-band data on a TCP socket (see tcp(7)).

              *  A pseudoterminal master in packet mode has seen a state
                 change on the slave (see ioctl_tty(2)).

              *  A cgroup.events file has been modified (see cgroups(7)).

       POLLOUT
              Writing is now possible, though a write larger that the avail‐
              able space in a socket or pipe will still block (unless O_NON‐
              BLOCK is set).

       POLLRDHUP (since Linux 2.6.17)
              Stream socket peer closed connection, or shut down writing
              half of connection.  The _GNU_SOURCE feature test macro must
              be defined (before including any header files) in order to
              obtain this definition.

       POLLERR
              Error condition (only returned in revents; ignored in events).
              This bit is also set for a file descriptor referring to the
              write end of a pipe when the read end has been closed.

       POLLHUP
              Hang up (only returned in revents; ignored in events).  Note
              that when reading from a channel such as a pipe or a stream
              socket, this event merely indicates that the peer closed its
              end of the channel.  Subsequent reads from the channel will
              return 0 (end of file) only after all outstanding data in the
              channel has been consumed.

       POLLNVAL
              Invalid request: fd not open (only returned in revents;
              ignored in events).

       When compiling with _XOPEN_SOURCE defined, one also has the follow‐
       ing, which convey no further information beyond the bits listed
       above:

       POLLRDNORM
              Equivalent to POLLIN.

       POLLRDBAND
              Priority band data can be read (generally unused on Linux).

       POLLWRNORM
              Equivalent to POLLOUT.

       POLLWRBAND
              Priority data may be written.

       Linux also knows about, but does not use POLLMSG.

   可以对照英文和中文翻译进行深入理解:http://www.cnblogs.com/alyssaCui/archive/2013/04/01/2993886.html

   不难理解,再贴一个示例demo:

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <poll.h>
#include <unistd.h>

#define W_DATA "howaylee"

int main(int argc, char* argv[])
{
    int ret = -1;
    int fd1 = -1;
    int fd2 = -1;
    char r_buf[12] = {0};
    struct pollfd fds[2] = {0};

    // open fd1
    fd1 = open(argv[1], O_RDWR|O_CREAT, S_IRWXU);
    if (-1 == fd1) {
        perror("open fd1 failed: ");
        return -1;
    }

    // write fd1
    ret = write(fd1, W_DATA, sizeof(W_DATA));
    if (-1 == ret) {
        perror("write fd1 failed: ");
        goto _OUT;
    }

    // lseek fd1 head
    ret = lseek(fd1, 0, SEEK_SET);
    if (-1 == ret) {
        perror("lseek fd1 failed: ");
        goto _OUT;
    }

    // open fd2
    fd2 = open(argv[2], O_RDWR|O_CREAT, S_IRWXU);
    if (-1 == fd2) {
        perror("open fd2 failed: ");
        return -1;
    }

    /* 阻塞,等待程序读写操作 */
    while (1) {
        // 初始化 pollfd
        fds[0].fd = fd1;
        // 可读
        fds[0].events = POLLIN;
        fds[1].fd = fd2;
        // 可写
        fds[1].events = POLLOUT;
        // poll
        ret = poll(fds, sizeof(fds)/sizeof(fds[0]), -1);
        if (-1 == ret) {
            perror("poll failed: ");
            goto _OUT;
        }

        // read fd1
        if (fds[0].revents & POLLIN) {
            // 清空缓存
            memset(r_buf, 0, sizeof(r_buf));
            ret = read(fd1, r_buf, sizeof(r_buf));
            if (-1 == ret) {
                perror("poll read failed: ");
                goto _OUT;
            }
            // printf("read = %s\\n", r_buf);
        }

        // write fd2
        if (fds[1].revents & POLLOUT) {
            ret = write(fd2, r_buf, sizeof(r_buf));
            if (-1 == ret) {
                perror("poll write failed: ");
                goto _OUT;
            }
            printf("write = %s\\n", r_buf);
        }
    }

    //close fd1 fd2
    close(fd1);
    close(fd2);
 _OUT:

    return ret;
}

 

 

 

 

asdf 

以上是关于poll的主要内容,如果未能解决你的问题,请参考以下文章

linux驱动之poll操作

Kafka consumer poll(long)与poll(Duration)的区别

poll() 不阻塞,立即返回

unix-poll

file_operations poll function

Kafka Source - 理解 Selector.poll() 的语义