IO多路转接 —— 认识 poll 函数

本文详细介绍了poll函数的工作原理,包括其参数配置、事件类型及返回值等,并通过实例展示了如何使用poll模型监听标准输入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、认识 poll 函数

1、第三个参数 timeout

2、第一、第二个参数

(1) 认识 pollfd 结构体类型

(2) 添加关注事件 / 判断事件是否就绪

3、返回值

二、使用poll模型监听标准输入


select模型的实现基于select函数,poll模型的实现也是基于 poll函数,poll可以看作是select的升级版,在功能层面是一样的,都是只负责等待事件就绪,不参与拷贝过程。

一、认识 poll 函数

poll函数的作用是等待某些事件是否就绪,函数声明如下:

1、第三个参数 timeout

这个参数是一个输入型参数,单位是毫秒,代表阻塞等待的时间,超过该时间就会变为非阻塞等待。

  • timeout = -1,代表永久阻塞等待
  • timeout = 0,代表永久非阻塞等待
  • timeout > 0,代表先阻塞等待 timeout 毫秒,超过这个时间变为非阻塞等待,poll函数返回

2、第一、第二个参数

为了记录哪些文件描述符需要被关注,我们一般会将这些文件描述符放到一个数组里。

  • 第一个参数:这个数组的元素首地址,元素类型是pollfd 结构体类型
  • 第二个参数:需要关注的文件描述符的数目。如果有多个文件描述符,我们可以通过这个参数来遍历数组中的文件描述符。

(1) 认识 pollfd 结构体类型

pollfd结构体包含了每一个需要内核关注的文件描述符的信息,比如这个文件描述符需要关注什么事件、有什么事件已经就绪了等等。pollfd 的结构体声明如下:

  • 第一个参数fd:你希望内核帮你关注哪个文件描述符
  • 第二个参数events:你希望内核帮你关注该文件描述符上的什么事件(读/写事件),事件类型以及设置方式在下面介绍。
  • 第三个参数revents:内核通知你该文件描述符上的某个事件就绪了。

(2) 添加关注事件 / 判断事件是否就绪

部分常用事件的类型如下:

事件描述是否可作为输入是否可作为输出
POLLIN数据(普通数据或者优先数据) 可读
POLLINNORM普通数据可读
POLLOUT数据(普通数据或者优先数据) 可写
POLLWRNORM普通数据可写

从下面这个图可以看出这些事件都是宏,我们可以以按位或的方式来为文件描述符添加需要关注的事件。short是16位,每一位都可以表示一个事件,也就是说我们最多可以传入16种事件。

比如我们希望内核帮我们关注 0号文件描述符上的读事件

struct pollfd rfds;    
rfds.fd = 0;              //希望内核帮我们关注0号文件描述符上的事件
rfds.events |= POLLIN;    //希望内核关注0号文件描述符上的读事件
//rfds.events = POLLIN | POLLOUT;    //希望既监听读事件又监听写事件
rfds.revents = 0;         //这个参数用于内核通知我们有事件就绪了,让我们赶紧来取

如果我们要判断读事件是否就绪

if(rfds.revents & POLLIN){
    std::cout << "读事件就绪了..." << std::endl;
}

3、返回值

poll函数调用出错,返回-1;

非阻塞模式下,返回0;

有事件就绪时,返回 有事件就绪的文件描述符的个数

二、使用poll模型监听标准输入

下面就使用 poll 模型来监听 标准输入(0号文件描述符)

#include <iostream>
#include <unistd.h>
#include <poll.h>
using namespace std;

int main()
{
    struct pollfd rfds;
    rfds.fd = 0;           //希望内核帮我们关注0号文件描述符上的事件
    rfds.events |= POLLIN; //希望内核关注0号文件描述符上的读事件
    rfds.revents = 0;      //这个参数用于内核通知我们有事件就绪了,让我们赶紧来取

    //int timeout = 0; //永久非阻塞等待
    int timeout = -1; //永久阻塞等待
    while (1)
    {
        int n = poll(&rfds, 1, timeout);
        if (n < 0)
        {
            std::cerr << "poll调用出错" << std::endl;
        }
        else if (n == 0)
        {
            std::cout << "数据还没有准备好" << std::endl;
            continue;
        }
        else
        {
            std::cout << "数据已经准备好了,赶紧来取吧" << std::endl;

            //如果上层一直不取,即不调用recv/read函数,该文件描述符上的读事件会一直处在就绪状态
            if (rfds.revents & POLLIN)
            {
                //说明该文件描述符上有读事件就绪了
                char buffer[128];
                ssize_t s = read(0, buffer, sizeof(buffer) - 1);
                if (s > 0)
                {
                    buffer[s] = 0;
                    std::cout << "读取到的内容为: " << buffer << std::endl;
                }
            }
        }
    }

    return 0;
}

测试结果一(非阻塞模式下)

 测试结果二(阻塞模式下)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值