当前位置: 首页 > news >正文

【计算机网络】IO复用方法(三)——poll

目录

一、poll 的基本概念

二、 poll 函数原型

 三、pollfd 结构详解

四、poll 的使用步骤

五、poll 示例代码

六、poll 的优缺点

七、注意事项


一、poll 的基本概念

poll 是一种 I/O 多路复用技术,用于监视多个文件描述符的状态(可读、可写或异常)。与 select 类似,在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪者。但 poll 解决了 select 的一些限制,如文件描述符数量的限制。

poll 通过一个 pollfd 结构数组来管理文件描述符,支持更多的事件类型,且没有固定数量的文件描述符限制(仅受系统资源限制)。

二、 poll 函数原型

poll 函数原型:

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

参数说明:

  • fds:pollfd 结构数组,指定我们感兴趣的所有文件描述符的可读、可写和异常事件。
  • nfds:数组长度
  • timeout:超时时间(毫秒),-1 表示无限等待

返回值:

  • 正数:就绪的文件描述符数量
  • 0:超时
  • -1:出错

 三、pollfd 结构详解

pollfd 结构定义如下:

struct pollfd {int fd;         // 文件描述符short events;   // 监视的事件short revents;  // 实际发生的事件
};

fd:指定文件描述符,

events:告诉poll监听fd上的哪些事件,是一系列的事件的按位或

revents:由内核修改,通知程序fd实际发生的哪些事件

可以在堆区malloc

常用事件标志:

  • POLLIN:数据可读
  • POLLOUT:可写
  • POLLERR:错误发生
  • POLLHUP:挂起
  • POLLNVAL:无效请求

四、poll 的使用步骤

定义一个 pollfd 结构数组,每个元素对应一个需要监视的文件描述符。结构包含文件描述符 fd、感兴趣的事件 events 和实际发生的事件 revents。

调用 poll 函数,传入 pollfd 数组、数组长度和超时时间(毫秒)。函数会阻塞直到有事件发生或超时。

检查每个 pollfd 的 revents 字段,确定哪些文件描述符就绪,并进行相应操作。

    五、poll 示例代码

    以下是一个简单的 poll 服务器示例,监听标准输入和套接字:

    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdlib.h>
    #include <poll.h>
    #define MAXFD 10
    int socket_init();
    void fds_init(struct pollfd fds[]){for(int i=0;i<MAXFD;i++){fds[i].fd=-1;fds[i].events=0;fds[i].revents=0;}
    }
    //添加元素
    void fds_add(struct pollfd fds[],int fd)
    {for(int i=0;i<MAXFD;i++){if(fds[i].fd=-1){fds[i].fd=fd;fds[i].events=POLLIN;//读事件fds[i].revents=0;break;//只找一个空位}}
    }
    //删除元素
    void fds_del(struct pollfd fds[],int fd)
    {for(int i=0;i<MAXFD;i++){if(fds[i].fd=fd){fds[i].fd=-1;fds[i].events=0;fds[i].revents=0;break;//只找一个空位}}
    }
    //监听套接字
    void accept_client(int sockfd,struct pollfd fds[]){int c=accept(sockfd,NULL,NULL);if(c<0){return;}printf("accpect c=%d\n",c);fds_add(fds,c);//将c添加
    }
    //连接套接字
    void recv_data(int c,struct pollfd fds[]){char buff[128];int n=recv(c,buff,127,0);if(n<=0){fds_del(fds,c);close(c);printf("client close\n");return;}printf("buff (c=%d)=%s\n",c,buff);send(c,"ok",2,0);
    }
    int main(){int sockfd=socket_init();//创建监听套接字,当客户端执行connect连接服务器时,读事件就绪if(sockfd==-1){exit(1);}struct pollfd fds[MAXFD];fds_init(fds);//空fds_add(fds,sockfd);while (1){int n=poll(fds,MAXFD,5000);//阻塞最长等待5s,当n>0,则if(n==-1){printf("poll errpr");}else if(n==0){printf("time out");}else{for(int i=0;i<MAXFD;i++){if(fds[i].fd==-1){continue;}if(fds[i].revents&POLLIN){if(fds[i].fd==sockfd){accept_client(sockfd,fds);}else{recv_data(fds[i].fd,fds);}}}}}}
    int socket_init(){//创建监听套接字int sockfd = socket(AF_INET,SOCK_STREAM,0);if( sockfd == -1){//创建套接字失败return -1;}struct sockaddr_in saddr;//ipv4专用,制定ip端口memset(&saddr,0,sizeof(saddr));//清空saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//绑定,通用套接字if( res == -1){printf("bind err\n");return -1;}res = listen(sockfd,5);//监听队列if( res == -1){return -1;}return sockfd;
    }

    主函数:创建套接字,该部分主要用于指定ip端口,实时监听;定义一个数组,该数组用于创建文件描述符;首先情况该数组,将所有的值置为-1;添加,将sockfd添加到数组fds中;添加文件描述符到fds数组中,此时fds拥有的用户关心的描述符socket fd和事件(该实例只关心读事件)。此时调用库,将数组以及结构体大小传进来,得到返回值。(正数则为找到就绪的)。判断是哪一种套接字,如果是监听套接字则accpet,反之recv。

    总结:找到哪个就绪的数据去处理。

    六、poll 的优缺点

    优点:

    • 没有文件描述符数量限制(select 通常限制为 1024)
    • 更高效,尤其在大量空闲文件描述符时
    • 更灵活的事件类型支持

    缺点:

    • 每次调用仍需遍历整个文件描述符集合
    • 在 Linux 上不支持文件描述符的动态增减(epoll 支持)
    • 性能在极高并发时可能不如 epol

    七、注意事项

    使用 poll 时应注意:

    • 确保 pollfd 数组中的 fd 字段有效
    • 正确处理 timeout 参数,避免 CPU 空转
    • 检查 revents 时使用位与操作(&)
    • 在多线程环境中注意线程安全问题
    • 某些系统可能不支持所有事件类型
    http://www.dtcms.com/a/569247.html

    相关文章:

  • 企业门户网站建设方案及报价广告网名
  • 【海思】在Ubuntu20.04上搭建可以成功编译Hi3559AV100的环境_20251104
  • Vue中iFrame跨窗口通信实现与源码解析
  • 做设计有哪些接私活的网站做钓鱼网站获利3万
  • git常用的指令-(工作中常用)
  • <数据集>yolo航拍交通目标识别数据集<目标检测>
  • 做标准件网站在ppt里面做网站链接
  • 关于网站建设的调研报告电商专业就业前景
  • 做百度糯米网站的团队做的比较好的个人网站
  • 天津市建设厅官方网站网站用绝对路径好还是相对路径seo
  • DevExpress WPF v25.2新功能预览 - 支持将JetBrains Rider与报表设计器集成
  • 力扣热题100道之102二叉树的层序遍历
  • SQLite Truncate Table: 完全删除表中的数据
  • 机器学习:数据集的划分
  • 学校网站建设费计入什么科目wordpress拖曳组件
  • 中国城乡和住房建设部网站wordpress微信商城
  • 零基础学JAVA--Day23(final关键字+抽象类及应用模板设计模式)
  • Linux虚拟机配置jupyter环境并在宿主机访问
  • 低空无人机“一网统飞”深度解构:从技术内核到产业落地,重构低空经济操作系统
  • MyBatis 中 resultMap、association、collection标签详解
  • 网站长期建设运营计划书自己怎么健网站视频下载
  • 网站强制qq弹窗代码专业网页设计制作价格
  • QuickRedis
  • 微信小程序开发案例 | 个人相册小程序(上)
  • JAVA多商户家政同城上门服务预约服务抢单派单+自营商城系统支持小程序+APP+公众号+h5
  • ELK 学习笔记
  • 在 Ubuntu 上快速配置 Node.js 环境(附问题说明)
  • discuz修改网站关键词wordpress微信qq登陆
  • 钦州公司做网站网络空间安全专业大学排名
  • ELK 企业级日志分析系统部署与实践