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;elsebreak;}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){// demochar 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; // 3sfor (;;){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:// 有事件就绪了,TODOcout << "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,还是用后面新出的这些接口比较好用

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

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

相关文章

【AOSP】手把手教你编译和调试AOSP源码

一、下载AOSP源码 在开始之前&#xff0c;我们先安装编译AOSP需要的一些系统基本依赖&#xff0c;如下命令 sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g-multilib libc6-dev-i386 lib32ncurses5-dev x11proto…

【图论】【分类讨论】LeetCode3017按距离统计房屋对数目

本文涉及的知识点 图论 分类讨论 本题同解 【差分数组】【图论】【分类讨论】【整除以2】3017按距离统计房屋对数目 LeetCode3017按距离统计房屋对数目 给你三个 正整数 n 、x 和 y 。 在城市中&#xff0c;存在编号从 1 到 n 的房屋&#xff0c;由 n 条街道相连。对所有 …

Centos7下docker安装jenkins【使用docker-compose图文教程】

个人记录 前置条件&#xff1a;安装Docker与Docker-compose Centos7安装Docker与Docker-compose【图文教程】 查看jenkins最新的版本 https://www.jenkins.io/download/ 配置docker-compose.yml vim docker-compose.yml按i进行编辑模式&#xff0c;粘贴如下内容。把image里…

11-pyspark的RDD的变换与动作算子总结

目录 前言 变换算子动作算子 前言 一般来说&#xff0c;RDD包括两个操作算子&#xff1a; 变换&#xff08;Transformations&#xff09;&#xff1a;变换算子的特点是懒执行&#xff0c;变换操作并不会立刻执行&#xff0c;而是需要等到有动作&#xff08;Actions&#xff09;…

java(7)之跳转语句

1、break跳转语句 说到break其实也不是跳转&#xff0c;它更像是一个终结语句&#xff0c;常用于在循环语句需要停止出现例如 while&#xff08;&#xff09;{ if&#xff08;&#xff09;{ break&#xff1b; }} 这样的形式或者 switch&#xff08;&#xff09;{ case…

蓝桥 python笔记14——KMP、字符串哈希、最长回文子串、字典树

目录 KMP 字符串哈希 最长回文子串 字典树 KMP 模式匹配问题&#xff1a; KMP算法&#xff1a; 用动规的思想求Next数组&#xff1a;如果后缀的i位置前缀的j位置&#xff0c;Next[i1]j1&#xff1b;如果后缀的i位置!前缀的j位置&#xff0c;那就用KMP算法&#xff0c;令jNe…

OpenCV图像处理——基于背景减除实现多目标追踪

1. 基本运动检测 基本运动检测方法的核心在于计算视频帧之间的差异&#xff0c;或者是将某一帧设定为“背景”&#xff0c;然后将其与后续的帧进行比较。这个过程在概念上非常简单&#xff1a;首先保存视频的第一帧作为背景参考&#xff0c;随后将这一帧与新接收到的帧进行逐像…

肖恩带你学C语言·文件操作(上)

1. 为什么使用文件 如果没有文件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失了&#xff0c;等再次运行程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进行持久化的保存&…

【攻防世界】FlatScience

dirsearch 扫描发现四个文件 在login.php 中发现 输入 http://61.147.171.105:61912/login.php/?debug 发现源码 <?php if(isset($_POST[usr]) && isset($_POST[pw])){$user $_POST[usr];$pass $_POST[pw];$db new SQLite3(../fancy.db);$res $db->query(…

Android 360度全景图功能

方法一&#xff1a;OpenGL ES 1.在build.gradle文件中添加依赖 allprojects {repositories {maven { url https://jitpack.io }} } 高版本AS中settings.gradle.kts&#xff1a; dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_RE…

蜂窝物联:智慧大田解决方案

蜂窝物联智慧大田解决方案集成了传感器、自动化控制、农情监测、物联网、无线通讯等技术&#xff0c;对与农作物生长及其物候期观测密切相关的土壤、空气、光照、热量等环境因子进行实时监测&#xff0c;智能预警&#xff1b;对田间灌溉电磁阀、水肥一体机进行远程智能自动化控…

9-浏览器必备插件

9-浏览器必备插件 1.Flash Copilot 浏览器超级助手 解决收藏夹 以及使用的办法 2.fehelper 本身还集成插件&#xff0c;满足开发使用 3.SuperCopy 超级复制 SuperCopy 超级复制 一键破解禁止右键、破解禁止选择、破解禁止复制、破解禁止粘贴&#xff0c;启用复制&#xff0c;…

SpringBoot | Spring Boot“整合Redis“

目录: 1. Redis 介绍2. Redis 下载安装3. Redis “服务开启”和“连接配置”4. Spring Boot整合Redis的“前期准备” :① 编写实体类② 编写Repository 接口③ 在“全局配置文件”中添加 “Redis数据库” 的 “相关配置信息” 5. Spring Boot整合“Redis” (案例展示) 作者简介…

Linux网卡与公网IP地址:一个不可随意配置的世界

在Linux系统的网络配置中&#xff0c;IP地址的配置是基础也是关键。许多人可能好奇&#xff1a;为何不能随意为Linux网卡配置公网IP地址&#xff0c;而私网IP地址似乎就可以随心所欲呢&#xff1f;本文将解开这些问题的答案&#xff0c;探索公网IP地址被严格管控的原因&#xf…

【UnityRPG游戏制作】Unity_RPG项目之界面面板分离和搭建

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

深度学习500问——Chapter05: 卷积神经网络(CNN)(4)

文章目录 5.18 卷积神经网络凸显共性的方法 5.18.1 局部连接 5.18.2 权值共享 5.18.3 池化操作 5.19 全连接、局部连接、全卷积与局部卷积 5.20 局部卷积的应用 5.21 NetVLAD池化 参考文献 5.18 卷积神经网络凸显共性的方法 5.18.1 局部连接 我们首先了解一个概念&#xff0c…

vue 打包 插槽 inject reactive draggable 动画 foreach pinia状态管理

在Vue项目中&#xff0c;当涉及到打包、插槽&#xff08;Slots&#xff09;、inject/reactive、draggable、transition、foreach以及pinia时&#xff0c;这些都是Vue框架的不同特性和库&#xff0c;它们各自在Vue应用中有不同的用途。下面我将逐一解释这些概念&#xff0c;并说…

8、滑动窗口-无重复字符的最长子串

解析&#xff1a; 遍历 判断map是否包含当前字符&#xff0c;如果包含&#xff1a; 获取重复的index下标在哪里获取len长度重新设置L指针,其中L指针不回退&#xff0c;也就是如果这个重复值在L前面那就忽略&#xff0c;如果是在后面那就设置为index1。 代码如下&#xff1a; …

二叉树算法练习day.2

102.二叉树的层序遍历 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&a…

小米手机澎湃OS,不Root查看电池健康

首先&#xff0c;在键盘拨号界面&#xff0c;输入*#*#284#*#*&#xff0c;会调用问题反馈APP来生成当前系统的故障日志&#xff0c;如果提示你需要授权什么就点确认 稍等几分钟&#xff0c;会得到一个压缩包&#xff0c;保存在目录MIUI/debug_log下 这里为了方便&#xff0c;我…