多路转接之poll(接口介绍,struct pollfd介绍,实现原理,实现非阻塞网络通信代码)
目录
poll
引入
介绍
函数原型
fds
struct pollfd
特点
nfds
timeout
取值
返回值
原理
如何实现关注多个fd?
如何确定哪个fd上有事件就绪?
如何区分事件类型?
判断某事件是否就绪的方法
代码
示例
总结
为什么说它解决了fd上限问题?
缺点
poll
引入
我们前面介绍了select -- 多路转接之select(fd_set介绍,参数详细介绍,优缺点),实现非阻塞式网络通信(代码+思路)-CSDN博客
- 随着文件数量增多(有新客户端来连接),文件上事件就绪的概率也就增大了
- 而等待就绪->通知用户层有事件就绪的过程涉及到多次遍历和拷贝,就绪次数多了,遍历和拷贝就多了
- 所以,会慢慢让效率变低
为了解决这些问题,出现了新的多路转接的方案 -- poll
介绍
是一种用于多路复用 I/O 事件的系统调用,它允许程序监视多个文件描述符,并等待其中的某些事件发生
- 它和select一样,只负责等待
- 它主要解决了select的两个弊端 -- fd有上限 和 参数重置问题
函数原型

fds
和select中三个位图的作用相同 -- 用于用户和内核之间的信息交流,但原理不同
struct pollfd
- 用户给内核传入要关注文件的fd和要关注的事件类型 -- 使用了pollfd中的fd,events字段
- 内核给用户返回该文件上的哪个事件已就绪 -- 使用fd,revents字段
特点
将输入和输出事件分离
- 而不是像select一样,用户和内核使用的是同一个结构(位图)
- 这里使用了两个变量给两方分别使用
nfds
fds中的元素个数
- 相当于需要关注的fd个数
timeout
等待事件的超时时间
- 以毫秒为单位,1000ms=1s
取值
- >0 -- 超时时间
- =0 -- 非阻塞,函数会立即返回
- -1
返回值
和select作用相同
- >0 -- 就绪的fd个数
- =0 -- 超时,没有事件就绪
- <0 -- 等待的文件中有已经关闭的文件
原理
如何实现关注多个fd?
这里的fds参数是一个结构体类型的指针
- 所以可以传入结构体数组 / 指向堆上空间的指针,后续可以动态扩容
所以,我们可以添加多个pollfd结构到数组中
如何确定哪个fd上有事件就绪?
遍历数组,检查每个结构的revents字段状态
如何区分事件类型?
将events/revents字段看作16个bit位,1个bit位可以对应一个事件类型
- 和标志位一样
判断某事件是否就绪的方法
- 以读事件为例:
- (某个指定pollfd结构中的revents & POLLIN) 是否等于1,等于1说明该事件已经就绪
代码
我们可以直接改select代码为poll版本,很简单:
- 不需要在循环内重复设置参数
- 把那些删掉后,修改调用select为poll即可,最多就创建一个pollfd结构体
#include "Log.hpp"
#include "socket.hpp"
#include <poll.h>static const int def_port = 8080;
static const int def_max_num = 1024;
static const int def_data = -1;
static const int no_data = 0;class poll_server
{
public:poll_server(){for (int i = 0; i < def_max_num; ++i){fds_[i].fd = def_data;fds_[i].events = no_data;fds_[i].revents = no_data;}}~poll_server(){listen_socket_.Close();}void start(){listen_socket_.Socket();listen_socket_.Bind(def_port);listen_socket_.Listen();int timeout = 1;// 固定数组第一项是监听套接字struct pollfd tl = {listen_socket_.get_fd(), POLLIN, no_data};fds_[0] = tl;while (true){int ret = poll(fds_, def_max_num, timeout);if (ret > 0) // 有事件就绪{handle();}else if (ret == 0) // 超时{continue;}else{perror("poll");break;}}}private:void receiver(int fd, int i){char in_buff[1024];int n = read(fd, in_buff, sizeof(in_buff) - 1);if (n > 0){in_buff[n - 1] = 0;std::cout << "get message: " << in_buff << std::endl;}else if (n == 0) // 客户端关闭连接{close(fd);lg(DEBUG, "%d quit", fd);fds_[i].fd = -1; // 重置该位置fds_[i].events = no_data;fds_[i].revents = no_data;}else{lg(ERROR, "fd: %d ,read error");}}void accepter(){std::string clientip;uint16_t clientport;int sock = listen_socket_.Accept(clientip, clientport);if (sock == -1){return;}else // 把新fd加入数组{struct pollfd t;int pos = 1000; //1sfor (; pos < def_max_num; ++pos){if (fds_[pos].fd == def_data) // 找到空位,但不能直接添加{break;}}if (pos != def_max_num){t.fd = sock;}else // 满了{//这里可以扩容lg(WARNING, "server is full,close %d now", sock);close(sock);}t.events = POLLIN;t.revents = no_data;fds_[pos] = t;}}void handle(){for (int i = 0; i < def_max_num; ++i) // 遍历数组{int fd = fds_[i].fd;if (fd != def_data) // 有效fd{if (fds_[i].revents & POLLIN) // 有事件就绪{if (fd == listen_socket_.get_fd()) // 获取新连接{accepter();}else // 读事件{receiver(fd, i);}}}}}private:MY_SOCKET listen_socket_;struct pollfd fds_[def_max_num];
};
示例
总结
为什么说它解决了fd上限问题?
因为poll里的数组大小由用户决定,而fd_set的大小已经被系统定死了,无法改变
缺点
但是,poll依然没有解决多次遍历的问题
- 用户层需要查看数组中每个结构的revents,看哪些文件的哪些事件就绪了
- 内核也需要遍历数组,查看需要关注哪些文件的哪些事件,查看是否有文件就绪
遍历成本由文件个数决定
- 虽然poll没有限制,但一旦数量过多,会影响遍历效率
所以,为了解决这个问题,提出了新的方案 -- epoll
它是目前效率最高的多路转接方案
相关文章:
多路转接之poll(接口介绍,struct pollfd介绍,实现原理,实现非阻塞网络通信代码)
目录 poll 引入 介绍 函数原型 fds struct pollfd 特点 nfds timeout 取值 返回值 原理 如何实现关注多个fd? 如何确定哪个fd上有事件就绪? 如何区分事件类型? 判断某事件是否就绪的方法 代码 示例 总结 为什么说它解决了fd上限问题? 缺点 poll 引入…...
两个月冲刺软考——位示图题型的例题讲解与分析;索引文件的详细解读
1. 位示图 位示图(Bitmap)是一种数据结构,用于表示和存储图像信息。在计算机科学中,位示图通常指的是一个二维的数组,每个元素称为一个像素,每个像素可以存储一个颜色值。 可以将位示图类比为电影院选座操作…...
SprinBoot+Vue校园数字化图书馆系统的设计与实现
目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平台Java领域优质…...
python如何加速计算密集型任务?
问题描述: 在python中,有一个函数,其功能是进行某种计算,需要传入一些参数,计算完成后传回结果,调用其一次大概要1s的时间,现在需要通过for循环调用其350次,保存每次调用结果&#…...
握手的方式展现人的性格及行为倾向
握手是人际交往中最常见的礼节之一,同时通过和对方握手,可以感知他的内心,进一步得知对方的性格及行为倾向。 心理学家认为,最好的握手方式是力度适中,动作沉稳,自然注视对方的眼睛,这种握手方…...
Java 排序算法详解
排序是计算机科学中的基本操作,Java 提供了多种排序算法来满足不同的需求。常见的排序算法包括冒泡排序、选择排序、插入排序、归并排序、快速排序和堆排序。本文将逐一介绍这些排序算法及其 Java 实现。 1. 冒泡排序 (Bubble Sort) 冒泡排序是一种简单的排序算法…...
vue3实现拖拽移动位置,拖拽过程中鼠标松开后元素还吸附在鼠标上并随着鼠标移动
发现问题 拖拽元素移动的时候,偶尔会出现拖拽过程中鼠标松开后元素还吸附在鼠标上并随着鼠标移动,要再按一下元素才会被放置下来。但是有时就正常。 问题分析 出现该问题的原因是:这个过程会触发H5原生的拖拽事件,并且不会监听…...
没有屋檐的房子-011
棺材 (下) 时过境迁这个成语描述了前因后果的两种概念的变化,时间推延和环境的变迁。问题是,时间是什么呢?是环境变化表征了时间的推延,还是时间推延导致了环境的变化?人在多数时候,…...
Puppeteer-Cluster:并行处理网页操作的新利器
在现代Web开发和自动化测试领域,高效地处理多个网页操作任务成为了许多开发者和测试工程师的迫切需求。传统的Puppeteer工具虽然功能强大,但在处理大量并发任务时可能会显得力不从心。为此,Puppeteer-Cluster应运而生,作为一个基于…...
使用Protocol Buffers传输数据
使用 Google Protocol Buffers(ProtoBuf)与 Kafka 结合来定义和传输数据,可以确保传输数据的结构性、可扩展性和高效性。以下是一个简单的步骤指南,帮助你实现生产者和消费者。 1. 定义 ProtoBuf 消息格式 首先,你需…...
chmod修改文件权限
0 Preface/Foreword 1 chmod使用方法 1.1 修改单个文件 命令如下: sudo chmod xyz fileName xyz: x, y, z分别代表一个8进制数字(0-7) 1.2 修改文件夹 命令如下: sudo chmod -R xyz folderName...
二叉树--python
二叉树 一、概述 1、介绍 是一种非线性数据结构,将数据一分为二,代表根与叶的派生关系,和链表的结构类似,二叉树的基本单元是结点,每个节点包括值和左右子节点引用。 每个节点都有两个引用(类似于双向链…...
matlab数据批量保存为excel,文件名,行和列的名称设置
Excel文件内数据保存结果如下: Excel文件保存结果如下: 代码如下: clear;clc; for jjjj1:10 %这个可以改 jname(jjjj-1)*10; %文件名中变数 这是EXCEL文件名字的一部分 根据自己需要改 jkkkk_num2str(jname); for …...
Pygame中Sprite类实现多帧动画3-2
3.2.3 设置帧的宽度、高度、范围及列数 通过如图6所示的代码设置帧的宽度、高度、范围及列数。 图6 设置帧的宽度、高度、范围及列数的代码 其中,frame_width、frame_height、rect和columns都是MySprite类的属性,在其__init__()方法中定义,…...
C#发送正文带图片带附件的邮件
1,开启服务,获取授权码。以QQ邮箱为例: 点击管理服务,进入账号与安全页面 2,相关设置参数,以QQ邮箱为例: 登录时,请在第三方客户端的密码输入框里面填入授权码进行验证。࿰…...
【C#跨平台开发详解】C#跨平台开发技术之.NET Core基础学习及快速入门
1. C#与.NET的发展历程 C#是由Microsoft开发的现代编程语言,最初伴随着.NET Framework发布。随着技术的进步,特别是针对跨平台开发的需求,Microsoft推出了.NET Core,这是一个开源且跨平台的框架,支持Windows、macOS和…...
请解释Java中的死锁产生的原因和解决方法。什么是Java中的并发工具类?请列举几个并解释其用途。
请解释Java中的死锁产生的原因和解决方法。 Java中的死锁是指两个或两个以上的线程在执行过程中,因为争夺资源而造成的一种相互等待的现象,若无外力作用,这些线程都将无法向前推进。死锁是并发编程中常见的问题,它会导致程序运行…...
三分钟带你看懂,低代码开发赋能办公方式转变
随着技术的不断进步,企业对办公效率和灵活性的需求日益增长。低代码开发作为一种新兴的开发模式,正在改变传统的办公方式,让非技术背景的业务人员也能参与到应用的创建和维护中来。本文将带你快速了解低代码开发如何赋能办公方式的转变。 什么…...
视频剪辑软件哪个好用?11款软件轻松上手,让创意视频流畅呈现!
视频剪辑已经涉及到很多个领域,视频剪辑软件的需求也是越来越普遍了。很多朋友在日常办公学习中,经常会遇到视频剪辑的问题。借助专业的视频剪辑软件,我们可以快速的对视频进行剪辑,制作出属于自己的作品。 市面上有各种各样的视频…...
pytest二次开发:生成用例参数
pytest.fixture是一个装饰器,用于声明一个fixture。Fixture是pytest中的一个核心概念,它提供了一种将测试前的准备代码(如设置测试环境、准备测试数据等)和测试后的清理代码(如恢复测试环境、删除临时文件等࿰…...
Intv_AI_MK11跨平台开发体验:在Windows WSL2中无缝使用GPU进行模型调试
Intv_AI_MK11跨平台开发体验:在Windows WSL2中无缝使用GPU进行模型调试 1. 为什么选择WSL2进行AI开发 对于习惯Windows系统的开发者来说,直接使用Linux环境进行AI模型开发往往面临诸多不便。WSL2(Windows Subsystem for Linux 2)…...
SQLite在线查看器:浏览器中的数据库管理革命
SQLite在线查看器:浏览器中的数据库管理革命 【免费下载链接】sqlite-viewer View SQLite file online 项目地址: https://gitcode.com/gh_mirrors/sq/sqlite-viewer 在数据驱动的时代,SQLite数据库无处不在——从移动应用到桌面软件,…...
终极指南:gh_mirrors/log/log构建流程解析:从CoffeeScript到Grunt自动化
终极指南:gh_mirrors/log/log构建流程解析:从CoffeeScript到Grunt自动化 【免费下载链接】log Console.log with style. 项目地址: https://gitcode.com/gh_mirrors/log/log 如何快速构建优雅的控制台日志工具?gh_mirrors/log/log项目…...
BiliBiliCCSubtitle:高效解决B站字幕处理难题全攻略
BiliBiliCCSubtitle:高效解决B站字幕处理难题全攻略 【免费下载链接】BiliBiliCCSubtitle 一个用于下载B站(哔哩哔哩)CC字幕及转换的工具; 项目地址: https://gitcode.com/gh_mirrors/bi/BiliBiliCCSubtitle 一、问题篇:字幕处理的真实困境与技术…...
为什么选择Drawflow:5大优势让你爱上这个流程图库
为什么选择Drawflow:5大优势让你爱上这个流程图库 【免费下载链接】Drawflow Simple flow library 🖥️🖱️ 项目地址: https://gitcode.com/gh_mirrors/dr/Drawflow Drawflow是一个简单而强大的JavaScript流程图库,专为创…...
koanf命令行参数解析:高级POSIX兼容标志处理指南
koanf命令行参数解析:高级POSIX兼容标志处理指南 【免费下载链接】koanf Simple, extremely lightweight, extensible, configuration management library for Go. Supports JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper. 项目地址:…...
论计算机科学的本质是什么?编程么?
计算机科学的本质不是编程。编程只是实现计算机科学思想的工具和手段,而非其内核。计算机科学的核心是“计算”与“问题求解”计算机科学(Computer Science, CS)本质上是一门研究信息与计算的理论基础,以及如何通过算法高效、可靠…...
AI时代:重塑核心竞争力
一、企业的核心竞争力重塑未来企业的护城河是AI构建的流程,而不是的数据。 过去我们说数据是石油,但在 LLM 时代,通用数据的价值在被快速拉平。而公司内部独特的、经过千锤百炼的工作流程、决策逻辑、操作手册,这些才是无法被轻易…...
使用Python轻松管理Word页脚
在日常的办公自动化中,处理Word文档是许多人绕不开的环节。无论是生成报告、合同,还是制作项目文档,Word都是一个不可或缺的工具。然而,当文档数量庞大,或者需要频繁更新时,那些看似简单的重复性任务&#…...
Python中CSV文件处理的常见累积错误及修正方案
在使用 Python 的 csv 模块处理学生成绩数据时,一个极易被忽视却影响结果准确性的典型问题是变量作用域与重用逻辑错误。如原始代码所示,grades [] 被定义在 for row in reader: 循环外部,导致每次迭代都将新学生的成绩追加到同一个列表中—…...


