Linux:IO多路转接之poll

文章目录

  • select的缺点
  • poll
    • struct pollfd
    • 解决缺点的方式
  • 代码实现

本篇总结的是poll的相关内容,在总结poll的内容前,先回顾一下select的缺点

select的缺点

select的缺点也比较明显

  1. 等待的fd是有上限的,在我们当前这个版本来说,它能等待的最大值是1024,也就是说超过来了这个1024我们的处理方式是直接把链接的这个socket丢弃
  2. 输入输出型参数比较多,数据拷贝的频率比较高
  3. 输入输出型参数比较多,每次都要对关心的fd进行事件重置
  4. 在用户层来说,在使用第三方数组进行管理fd的时候,要进行很多次的遍历,在内核中检测fd的事件就绪的时候,也要进行遍历

那么为了解决上述的这些问题,我们引入了poll的概念:

poll

先看一下poll的相关接口

在这里插入图片描述
poll的接口和select的接口几乎一样,所以使用起来基本没什么区别,这里出现了一个新的结构体,pollfd:

struct pollfd

在这里插入图片描述
那么到这里就可以看一下poll是如何解决select的缺点的:

解决缺点的方式

1. 等待的fd是有上限的

在select当中,一个很大的问题是有上限,而这个问题出现的原因是因为select的设计当中,最根源的问题在于它的位图大小决定了只能容纳1024个新的请求,再多了就不能容纳了,所以为了解决这个问题,poll直接设置成无限大小,只要操作系统和内存能放得下,那就能放得下,这是poll对于select的一个解决方案

2. 输入输出型参数比较多

这个问题poll也成功的解决了,poll的解决方案是直接定义一个结构体:

在这里插入图片描述

在这个结构体当中,存在有fd,events,revents,那么这就意味着可以免去拷贝的工作,直接在结构体当中进行设置即可,对于不同类型的参数,用位图来进行表示,存储在short当中:

在这里插入图片描述
在这里插入图片描述
至此,对于输入输出型参数太多导致的问题也被poll解决了

3. 遍历

但是遗憾的是,poll并没有解决遍历带来的效率问题,并且更为严重的是,poll还可以无限的增加数组中元素的个数,所以理论上来说是可以存放100000个数组内容的,这就给遍历带来了相当大的问题,所以遍历这件事poll并没有解决,这是Linux的这种设计模式决定确实不能解决的,具体解决只能留到epoll来解决了

代码实现

整体来说只要会用select,poll就是在它之上进行优化的,所以我只是对于select的代码进行了一些更变就有了poll的代码逻辑

#pragma once

#include <iostream>
#include <poll.h>
#include <sys/time.h>
#include "Socket.hpp"

using namespace std;

static const uint16_t defaultport = 8888;
static const int fd_num_max = 64;
int defaultfd = -1;
int non_event = 0;

class PollServer
{
public:
    PollServer(uint16_t port = defaultport) : _port(port)
    {
        for (int i = 0; i < fd_num_max; i++)
        {
            _event_fds[i].fd = defaultfd;
            _event_fds[i].events = non_event;
            _event_fds[i].revents = non_event;

            // cout << "fd_array[" << i << "]" << " : " << fd_array[i] << endl;
        }
    }
    bool Init()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();

        return true;
    }
    void Accepter()
    {
        // 我们的连接事件就绪了
        string clientip;
        uint16_t clientport = 0;
        int sock = _listensock.Accept(&clientip, &clientport); // 会不会阻塞在这里?不会
        if (sock < 0)
            return;
        lg(Info, "accept success, %s: %d, sock fd: %d", clientip.c_str(), clientport, sock);

        // sock -> fd_array[]
        int pos = 1;
        for (; pos < fd_num_max; pos++) // 第二个循环
        {
            if (_event_fds[pos].fd != defaultfd)
                continue;
            else
                break;
        }
        if (pos == fd_num_max)
        {
            lg(Warning, "server is full, close %d now!", sock);
            close(sock);
            // 扩容
        }
        else
        {
            // fd_array[pos] = sock;
            _event_fds[pos].fd = sock;
            _event_fds[pos].events = POLLIN;
            _event_fds[pos].revents = non_event;
            PrintFd();
            // TODO
        }
    }
    void Recver(int fd, int pos)
    {
        // demo
        char buffer[1024];
        ssize_t n = read(fd, buffer, sizeof(buffer) - 1); // bug?
        if (n > 0)
        {
            buffer[n] = 0;
            cout << "get a messge: " << buffer << endl;
        }
        else if (n == 0)
        {
            lg(Info, "client quit, me too, close fd is : %d", fd);
            close(fd);
            _event_fds[pos].fd = defaultfd; // 这里本质是从select中移除
        }
        else
        {
            lg(Warning, "recv error: fd is : %d", fd);
            close(fd);
            _event_fds[pos].fd = defaultfd; // 这里本质是从select中移除
        }
    }
    void Dispatcher()
    {
        for (int i = 0; i < fd_num_max; i++) // 这是第三个循环
        {
            int fd = _event_fds[i].fd;
            if (fd == defaultfd)
                continue;

            if (_event_fds[i].revents & POLLIN)
            {
                if (fd == _listensock.Fd())
                {
                    Accepter(); // 连接管理器
                }
                else // non listenfd
                {
                    Recver(fd, i);
                }
            }
        }
    }
    void Start()
    {
        _event_fds[0].fd = _listensock.Fd();
        _event_fds[0].events = POLLIN;
        int timeout = 3000; // 3s
        for (;;)
        {
            int n = poll(_event_fds, fd_num_max, timeout);
            switch (n)
            {
            case 0:
                cout << "time out... " << endl;
                break;
            case -1:
                cerr << "poll error" << endl;
                break;
            default:
                // 有事件就绪了,TODO
                cout << "get a new link!!!!!" << endl;
                Dispatcher(); // 就绪的事件和fd你怎么知道只有一个呢???
                break;
            }
        }
    }
    void PrintFd()
    {
        cout << "online fd list: ";
        for (int i = 0; i < fd_num_max; i++)
        {
            if (_event_fds[i].fd == defaultfd)
                continue;
            cout << _event_fds[i].fd << " ";
        }
        cout << endl;
    }
    ~PollServer()
    {
        _listensock.Close();
    }

private:
    Sock _listensock;
    uint16_t _port;
    struct pollfd _event_fds[fd_num_max]; // 数组, 用户维护的!
    // struct pollfd *_event_fds;

    // int fd_array[fd_num_max];
    // int wfd_array[fd_num_max];
};

而在实际的使用当中,除非是在特殊的环境下,比如是比较老的平台,否则一般不用select,还是用后面新出的这些接口比较好用

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

信号处理之(文件批处理+小波分解+波形图的生成)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、前期准备工作之数据自动读取二、前期准备工作之信号分解&#xff08;小波分解&#xff09;三、前期准备工作之数据可视化&#xff08;波形图展示&#xff0…

Redis的配置文件详解

单位&#xff1a;Redis配置对大小写不敏感&#xff01; 注意这里&#xff1a;任何写法都可&#xff0c;不区分大小写。 units are case insensitive so 1GB 1Gb 1gB are all the same.包含&#xff1a;搭建Redis集群时&#xff0c;可以使用includes包含其他配置文件网络&…

个推助力小米汽车APP实现智能用户触达,打造智能出行新体验

4月3日&#xff0c;小米SU7首批交付仪式在北京亦庄的小米汽车工厂总装车间举行&#xff0c;全国28城交付中心也同步开启首批交付。随着小米SU7系列汽车的正式发售和交付&#xff0c;小米汽车APP迎来了用户体量的爆发式增长。 小米汽车APP是小米汽车官方推出的手机应用&#xff…

大型语言模型(LLMs)面试常见问题解析

概述 这篇文章[1]是关于大型语言模型&#xff08;LLMs&#xff09;的面试问题和答案&#xff0c;旨在帮助读者准备相关职位的面试。 token&#xff1f; 在大型语言模型中&#xff0c;token 指的是什么&#xff1f; 分词&#xff08;Tokenization&#xff09;&#xff1a;可以将…

力扣热题100_链表_138_随机链表的复制

文章目录 题目链接解题思路解题代码 题目链接 138. 随机链表的复制 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&a…

事件时间+时间窗口,最后一个窗口不执行问题踩坑与源码分析

事件时间时间窗口&#xff0c;最后一个窗口不执行问题踩坑与源码分析 1. 结论 在使用事件时间和时间窗口的过程中&#xff0c;当最后一个事件的事件时间未达到时间窗口的最大时间&#xff0c;窗口不会触发。 举例说明&#xff0c;在按小时的滚动窗口中&#xff0c;假设当前时…

开启虚拟机时出现此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态怎么解决

问题描述 虚拟机安装完成后&#xff0c;点击开启此虚拟机弹出系统提示 原因分析&#xff1a; Intel VT-x 处于禁用状态&#xff0c;需要开启。 解决方案&#xff1a; 以联系小新笔记本电脑为例&#xff0c;进入BIOS界面&#xff0c;将Intel Virtual Technology设置成Enabl…

STL--迭代器的介绍

一.迭代器介绍&#x1f357; 迭代器是 C 标准模板库&#xff08;STL&#xff09;中的一个重要概念。简单来说&#xff0c;迭代器就像是一个指针&#xff0c;用于访问和遍历容器中的元素&#xff08;比如数组、链表、集合等&#xff09;。迭代器提供了一种统一的方法来访问容器…

力扣1448---统计二叉树中好节点的数量(Java、DFS、中等题)

题目描述&#xff1a; 给你一棵根为 root 的二叉树&#xff0c;请你返回二叉树中好节点的数目。 「好节点」X 定义为&#xff1a;从根到该节点 X 所经过的节点中&#xff0c;没有任何节点的值大于 X 的值。 示例 1&#xff1a; 输入&#xff1a;root [3,1,4,3,null,1,5] 输出…

开启新纪元中凡工业装备邀您参观2024第13届生物发酵展

参展企业介绍 中凡工业是一家专注于螺旋板式换热器以及相关非标设备制造的生产厂家。公司产品主要应用于环保废水、污水处理、可再生能源、食品、药化、焦化、农化、精细化工等行业&#xff0c;为这些行业解决生产工艺中的液体加热&#xff0c;液体冷却&#xff0c;气体冷凝&a…

聚观早报 | 沃尔沃发布一季度全球销量;苹果将举办财报电话会议

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 4月07日消息 沃尔沃发布一季度全球销量 苹果将举办新财报电话会议 荣耀Magic6支持5.5G通信 特斯拉将建最大超级充…

Word技巧之【允许修改受保护文档的部分内容】

给Word文档设置“限制编辑”&#xff0c;可以保护文档不能随意编辑更改&#xff0c;但如果文档中有部分内容&#xff0c;是需要供打开文档的人可以修改&#xff0c;要怎么使这部分内容允许修改呢&#xff1f;下面一起来看看&#xff0c;如何设置Word文档中允许部分内容可修改。…

政安晨:【深度学习神经网络基础】(三)—— 激活函数

目录 线性激活函数 阶跃激活函数 S型激活函数 双曲正切激活函数 修正线性单元 Softmax激活函数 偏置扮演什么角色&#xff1f; 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨…

Java Spring IoCDI :探索Java Spring中控制反转和依赖注入的威力,增强灵活性和可维护性

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;Java Spring IoC&DI :探索Java Spring中控制反转和依赖注入的威力,增强灵活性和可维护性 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 前提小知识:高内…

12-2-CSS 字体图标

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 CSS 字体图标1 字体图标的产生2 字体图标的优点3 字体图标的下载4 字体图标的…

LangChain-10(2) 加餐 编写Agent获取本地Docker运行情况 无技术含量只是思路

可以先查看 上一节内容&#xff0c;会对本节有更好的理解。 安装依赖 pip install langchainhub编写代码 核心代码 tool def get_docker_info(docker_name: str) -> str:"""Get information about a docker pod container info."""result…

隐私计算实训营学习八:隐语SCQL的开发实践

文章目录 一、SCQL使用集成最佳实践1.1 SCQL使用流程1.2 SCQL部署1.3 SCQL使用示例 二、SCQL工作原理三、使用SecretNote上手体验SCQL 一、SCQL使用集成最佳实践 1.1 SCQL使用流程 SCQL使用&#xff1a; SCQL 开放 API 供⽤户使⽤/集成。可以使⽤SCDBClient上⼿体验(类似与My…

归一化技术比较研究:Batch Norm, Layer Norm, Group Norm

归一化层是深度神经网络体系结构中的关键&#xff0c;在训练过程中确保各层的输入分布一致&#xff0c;这对于高效和稳定的学习至关重要。归一化技术的选择&#xff08;Batch, Layer, GroupNormalization&#xff09;会显著影响训练动态和最终的模型性能。每种技术的相对优势并…

CSS - 你实现过宽高自适应的正方形吗

难度 难度级别:中高级及以上 提问概率:80% 宽高自适应的需求并不少见,尤其是在当今流行的大屏系统开发中更是随处可见,很显然已经超越了我们日常将div写死100px这样的范畴,那么如何实现一个宽高自适应的正方形呢?这里提出两种实现方案。…

【Linux】进程初步理解

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1. 冯诺依曼体系结构1.1 认识冯诺依曼体系结构1.2 存储金字塔 2. 操作系统2.1 概念2.2 结构2.3 操作系统的管理 3. 进程3.1 进程描述3.2 Linux下的PCB 4. task_struct本身内部属性4.1 启动4.2 进程的创建方式4.2.1 父…