高级IO_多路转接之Poll

news2025/2/27 21:12:25

文章目录

  • 前言
  • 一、poll
  • 二、poll使用步骤
  • 总结


前言

上一章我们学习了select,但是select作为早期的多路转接接口,缺点十分明显,于是又出现poll和epoll等接口,今天我们就来学习一下poll的使用


提示:以下是本篇文章正文内容,下面案例可供参考

一、poll

在这里插入图片描述
参数struct pollfd *fds,它其实传的是一个struct pollfd数组,其结构体成员介绍如下。

  • fd设置为要关心的fd;
  • events是一个输入型参数,用来告知poll要关心的事件,比如说POLLIN就是让它关心读事件;
  • revents是一个输出型参数,当poll检测到关心的fd有events的资源就绪时,就会返回并将该fd对应的revents设置为就绪events。

之前我们使用select,还需要用到一个辅助数组来保存我们需要关心的fds,因为它的大部分参数都是输入输出型参数。而poll采用了struct pollfd结构体的方式让输入输出型参数分离互不影响,也是弥补了select的这一缺点。

参数nfds_t nfds,它用于告知poll需要关心的fd数量,其实就是fds数组的元素个数。

参数int timeout,功能上与select的timeout一样,不过poll舍弃了传struct timeval结构体的方式,直接传一个int整形就可以了,其单位为ms。

二、poll使用步骤

poll的使用步骤与select类似。

#include "Socket.hpp"
#include <poll.h>

#define MAX_POLLFDS 1024
#define INVALID_FD -1

const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8080;

class PollServer
{
public:
    PollServer(uint16_t port = default_port)
        : _port(port) {}

    inline void InitFds()
    {
        _pollfds[0].fd = _listensock._sockfd;
        _pollfds[0].events = POLLIN;
        for (int i = 1; i < MAX_POLLFDS; ++i)
        {
            _pollfds[i].fd = INVALID_FD;
        }
    }
    void Init()
    {
        _listensock.Init();
        _listensock.Bind(AF_INET, default_ip, _port);
        _listensock.Listen();
        InitFds();
    }

    void Print()
    {
        std::cout << "现有fds: ";
        for (int i = 0; i < MAX_POLLFDS; ++i)
        {
            if (_pollfds[i].fd == INVALID_FD)
            {
                continue;
            }
            std::cout << _pollfds[i].fd << " ";
        }
        std::cout << std::endl;
    }

    void Accepter()
    {
        struct sockaddr_in tmp;
        socklen_t len = sizeof tmp;
        int newfd = accept(_listensock._sockfd, (struct sockaddr *)&tmp, &len);
        for (int i = 0; i < MAX_POLLFDS; ++i)
        {
            if (_pollfds[i].fd == INVALID_FD)
            {
                _pollfds[i].fd = newfd;
                _pollfds[i].events = POLLIN;
                _pollfds[i].revents = 0;
                lg(Info, "Get A New Sockfd:%d", newfd);
                break;
            }
            if (i == MAX_POLLFDS)
            {
                lg(Warning, "Fds Is Full, Newfd:%d Closed...", newfd);
                close(newfd);
                return;
            }
        }
    }

    void Handler(int fd, int i)
    {
        char buffer[1024];
        memset(buffer, 0, sizeof buffer);
        int n = read(fd, buffer, sizeof buffer - 1);
        if (n > 0)
        {
            buffer[n] = 0;
            std::string mes = buffer;
            std::cout << mes;
            _pollfds[i].revents = 0;
        }
        else if (n < 0)
        {
            lg(Warning, "Read Error...");
            close(fd);
            _pollfds[i].fd = INVALID_FD;
        }
        else
        {
            lg(Info, "Foreign Host Closed...");
            close(fd);
            _pollfds[i].fd = INVALID_FD;
        }
    }

    void Dispatcher()
    {
        for (int i = 0; i < MAX_POLLFDS; ++i)
        {
            if (_pollfds[i].fd == INVALID_FD)
            {
                continue;
            }
            else if (_pollfds[i].revents & POLLIN)
            {
                if (_pollfds[i].fd == _listensock._sockfd)
                {
                    // accept
                    Accepter();
                    continue;
                }
                Handler(_pollfds[i].fd, i);
            }
        }
    }

    void Start()
    {
        while (1)
        {
            Print();
            int n = poll(_pollfds, MAX_POLLFDS, 5000);
            if (n == 0)
            {
                lg(Info, "Poll Time Out...");
                continue;
            }
            else if (n < 0)
            {
                lg(Warning, "Poll Error...");
                std::cout << "errno:" << errno << " strerror:" << strerror(errno) << std::endl;
            }
            else
            {
                Dispatcher();
            }
        }
    }

    ~PollServer()
    {
        _listensock.Close();
    }

private:
    struct pollfd _pollfds[MAX_POLLFDS];
    Socket _listensock;
    uint16_t _port;
};

总结

poll相比较于select,弥补了两个缺点。

  1. 不再需要繁琐地更新需要关心的fd和其对应事件。
  2. 可关心的fd数量不再受其接口内置的数据结构大小限制,可以根据用户需求自由调整。

但是仍然还有缺点,那就是每次进行一次poll都是一次从用户态拷贝数据到内核态的过程。 还有还是需要一些for循环遍历那些已经就绪了的fd。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1894661.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7.4总结

今天写了几道题目 最近&#xff0c;一年级学生马克西姆学习了科拉兹猜想&#xff0c;但他在讲课时没有太注意&#xff0c;所以他认为猜想中提到了以下过程&#xff1a; 有一个变量 $$$x$$$ 和一个常数 $$$y$$$ 。下面的操作要执行 $$$k$$$ 次&#xff1a; - 将 $$$x$$$ 增加…

MySQL资讯|2024年MySQL第一个长期支持版本8.4发布

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者、ACDU成员 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注…

React 中如何使用 Monaco

Monaco 是微软开源的一个编辑器&#xff0c;VSCode 也是基于 Monaco 进行开发的。如果在 React 中如何使用 Monaco&#xff0c;本文将介绍如何在 React 中引入 Monaco。 安装 React 依赖 yarn add react-app-rewired --dev yarn add monaco-editor-webpack-plugin --dev yarn…

【Android面试八股文】Android性能优化面试题:怎样检测函数执行是否卡顿?

文章目录 卡顿一、可重现的卡顿二、不可重现的卡顿第一种方案: 基于 Looper 的监控方法第二种方案:基于 Choreographer 的监控方法第三种方案:字节码插桩方式第四种方案: 使用 JVMTI 监听函数进入与退出总结相关大厂的方案ArgusAPMBlockCanaryQQ空间卡慢组件Matrix微信广研参…

DBSCAN数学表示

DBSCAN&#xff08;Density-Based Spatial Clustering of Applications with Noise&#xff09;&#xff0c;是判断一个点集&#xff0c;其中哪些点是聚类&#xff0c;哪些点是噪声点。 和kmean方法相比&#xff0c;这种ACM方法还是比较难以写成解析表达式的。 是半径。N是点集…

C语言程序是怎么在计算机中运行起来的

hello.c #include <stdio.h>int main(){printf("hello,world\n");return 0; }这段 C语言程序的代码能被编程人员读懂&#xff0c;但是计算机系统读不懂。C语言、C、java 这些高级编程语言本质上还是人类用的语言而不是计算机用的语言。 为了能在计算机上运行这…

传统数据处理系统存在的问题

传统应用的数据系统架构设计时&#xff0c;应用直接访问数据库系统。当用户访问量增加时&#xff0c;数据库无法支撑日益增长的用户请求的负载&#xff0c;从而导致数据库服务器无法及时响应用户请求&#xff0c;出现超时的错误。 出现这种情况以后&#xff0c;在系统架构上就采…

Redis 7.x 系列【18】事务

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 概述2. 命令2.1 MULTI2.2 EXEC2.3 DISCARD2.4 WATCH2.5 UNWATCH 3. 事务中的错误4.…

动态校验列表数据方案

背景&#xff1a;当select 选择A 的时候是必填&#xff0c;选B的时候是非必填 那么我们需要监听 selec 变化时候对 列表的 :edit-rules“validRulesList” 进行重新赋值必填校验的true, &#xff08;跟对列表内上传文件&#xff0c;对列表文件进行赋值名字一样道理&#xff0c;…

在Linux上查找文件的2个好用的命令

1. locate xx &#xff08;查找带xx字符的所有文件或目录&#xff09; 在终端输入命令 locate lua&#xff0c;可以看到&#xff0c;所有带lua字符的文件或目录都会被搜索出来。 2. find / -name xx &#xff08;查找名为xx的文件或目录&#xff09; 在终端输入命令 find …

Java通过GeoLite2-City.mmdb 进行IP信息查询地理定位和经纬度筛选。

引入依赖 <dependency><groupId>com.maxmind.geoip2</groupId><artifactId>geoip2</artifactId><version>4.2.0</version> </dependency>下载数据文件&#xff1a;https://download.lin2ur.cn/GeoLite2/ package com.cqclo…

Springboot+Vue3开发学习笔记《2》

SpringbootVue3开发学习笔记《2》 博主正在学习SpringbootVue3开发&#xff0c;希望记录自己学习过程同时与广大网友共同学习讨论。 总共涉及两部分&#xff0c;第一部分为基础部分学习&#xff0c;第二部分为实战部分。 一、学习路径 1.1 基础部分 配置文件整合MyBatisBea…

#### golang中【堆】的使用及底层 ####

声明&#xff0c;本文部分内容摘自&#xff1a; Go: 深入理解堆实现及应用-腾讯云开发者社区-腾讯云 数组实现堆 | WXue 堆&#xff08;Heap&#xff09;是实现优先队列的数据结构&#xff0c;Go提供了接口和方法来操作堆。 应用 package mainimport ("container/heap&q…

深度解析Java世界中的对象镜像:浅拷贝与深拷贝的奥秘与应用

在Java编程的浩瀚宇宙中&#xff0c;对象拷贝是一项既基础又至关重要的技术。它直接关系到程序的性能、资源管理及数据安全性。然而&#xff0c;提及对象拷贝&#xff0c;不得不深入探讨其两大核心类型&#xff1a;浅拷贝&#xff08;Shallow Copy&#xff09;与深拷贝&#xf…

2024最全软件测试面试八股文(答案+文档+视频讲解)

Part1 1、你的测试职业发展是什么&#xff1f; 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自…

动态规划入门,从简单递归到记忆化搜索到动态规划

动态规划入门&#xff0c;从简单递归到记忆化搜索到动态规划 打家劫舍 class Solution {private int nums[];public int rob(int[] nums) {this.nums nums;return dfs(nums.length - 1);}public int dfs(int i){if (i < 0){return 0;}int res Math.max(dfs(i - 1), dfs(i…

Python学习篇:Python基础知识(三)

目录 1 Python保留字 2 注释 3 行与缩进 ​编辑4 多行语句 5 输入和输出 6 变量 7 数据类型 8 类型转换 9 表达式 10 运算符 1 Python保留字 Python保留字&#xff08;也称为关键字&#xff09;是Python编程语言中预定义的、具有特殊含义的标识符。这些保留字不能用作…

【UML用户指南】-28-对体系结构建模-部署

目录 1、名称 2、节点与制品 2.1、结点与制品相同&#xff1a; 2.2、不同 3、组织结点 4、连接 5、常用建模技术 5.1、对处理器和设备建模 5.2、对制品的分布建模 正如制品一样&#xff0c;结点存在于物质世界中&#xff0c;在对系统的物理方面建模中它是一个重要构造…

Python——面向对象编程(类和对象)2

目录 私有属性和私有方法 01.应用场景及定义方式 02.伪私有属性和私有方法 继承 1.1继承的概念、语法和特点 1.继承的语法&#xff1a; 2.专业术语&#xff1a; 3.继承的传递性 1.2方法的重写 1.覆盖父类的方法 2.对父类方法进行扩展 关于super 1.3 父类的私有属性和…

数据看板/可视化大屏的实际价值到底是什么?详解数据可视化的实用之处

数据驾驶舱/数据看板/可视化大屏的实际价值&#xff0c;取决于使用者的实际需求。 华而不实&#xff1f;华就是实&#xff01; 关于可视化大屏最广泛的争议&#xff0c;便是对其“华而不实”的批评&#xff0c;认为可视化大屏缺乏技术含量&#xff0c;只是一钟比较高级的“装饰…