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

Linux多路转接之poll

文章目录

  • 一、poll的认识
  • 二、编写poll方案服务器
  • 三、poll方案多路转接的总结

一、poll的认识

多路转接技术是在不断更新进步的,一开始多路转接采用的是select方案,但是select方案存在的缺点比较多,所以在此基础上改进,产生了poll方案。poll是多路转接的另一种方案,它使用起来比select方案简单很多,也比较好用。

poll函数原型:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

select方案的最大缺点就在于它的输入和输出都是用同一个参数,比如我们将设置好的需要等待的文件描述符集合输入进去使用的是readfds这个参数,它将文件描述符集合中读事件就绪的文件描述符输出出来也是使用readfds这个参数。这就导致我们每一次都需要重置参数,所以这给我们使用select增加了很大的成本。并且fd_set是位图结构,所以就导致select函数可以检测的文件描述符数量是有上限的。

针对select方案的上述缺点,poll进行了改进:poll的参数struct pollfd *fds其实是一个结构体数组,它里面的结构如下图所示:

在这里插入图片描述
其中fd表示要等待的文件描述符是什么,events表示我们要传递进去的等待事件是什么,revents表示内核给我们传递出来的事件。这个结构和select就有很大的差别,它把原来select的readfds拆分成了两个参数,将输入和输出进行了分离。第二个参数nfds_t nfds其实就是一个整数,代表结构体数组的元素个数。第三个参数int timeout代表等待时间,当该参数设置为-1时代表永久阻塞,当该参数设置为0时代表非阻塞,当该参数设置大于0时代表在规定时间内阻塞,超时之后返回0。

pollfd结构体中的events和revents可以设置不同的事件,它们常用的取值有:

在这里插入图片描述

在这里插入图片描述

二、编写poll方案服务器

我们可以编写一个poll方案的多路转接服务器,来演示一下poll函数接口的使用:

Sock.hpp:

#pragma once#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <signal.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <cerrno>
#include <cassert>class Sock
{
public:static const int gbacklog = 20;static int Socket(){int listenSock = socket(PF_INET, SOCK_STREAM, 0);if (listenSock < 0){exit(1);}int opt = 1;setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));return listenSock;}static void Bind(int socket, uint16_t port){struct sockaddr_in local; // 用户栈memset(&local, 0, sizeof local);local.sin_family = PF_INET;local.sin_port = htons(port);local.sin_addr.s_addr = INADDR_ANY;// 2.2 本地socket信息,写入sock_对应的内核区域if (bind(socket, (const struct sockaddr *)&local, sizeof local) < 0){exit(2);}}static void Listen(int socket){if (listen(socket, gbacklog) < 0){exit(3);}}static int Accept(int socket, std::string *clientip, uint16_t *clientport){struct sockaddr_in peer;socklen_t len = sizeof(peer);int serviceSock = accept(socket, (struct sockaddr *)&peer, &len);if (serviceSock < 0){// 获取链接失败return -1;}if(clientport) *clientport = ntohs(peer.sin_port);if(clientip) *clientip = inet_ntoa(peer.sin_addr);return serviceSock;}
};

PollServer.cc:

#include <iostream>
#include <poll.h>
#include "Sock.hpp"#define NUM 1024
struct pollfd fdsArray[NUM]; // 保存历史上所有的合法fd#define DFL -1using namespace std;static void showArray(struct pollfd arr[], int num)
{cout << "当前合法sock list# ";for (int i = 0; i < num; i++){if (arr[i].fd == DFL)continue;elsecout << arr[i].fd << " ";}cout << endl;
}static void usage(std::string process)
{cerr << "\nUsage: " << process << " port\n"<< endl;
}
// readfds: 现在包含就是已经就绪的sock
static void HandlerEvent(int listensock)
{for (int i = 0; i < NUM; i++){if (fdsArray[i].fd == DFL)continue;if (i == 0 && fdsArray[i].fd == listensock){// 我们是如何得知哪些fd,上面的事件就绪呢?if (fdsArray[i].revents & POLLIN){// 具有了一个新链接cout << "已经有一个新链接到来了,需要进行获取(读取/拷贝)了" << endl;string clientip;uint16_t clientport = 0;int sock = Sock::Accept(listensock, &clientip, &clientport); // 不会阻塞if (sock < 0)return;cout << "获取新连接成功: " << clientip << ":" << clientport << " | sock: " << sock << endl;// read/write -- 不能,因为你read不知道底层数据是否就绪!!select知道!// 想办法把新的fd托管给select?如何托管??int i = 0;for (; i < NUM; i++){if (fdsArray[i].fd == DFL)break;}if (i == NUM){cerr << "我的服务器已经到了最大的上限了,无法在承载更多同时保持的连接了" << endl;close(sock);}else{fdsArray[i].fd = sock; // 将sock添加到select中,进行进一步的监听就绪事件了!fdsArray[i].events = POLLIN;fdsArray[i].revents = 0;showArray(fdsArray, NUM);}}} // end if (i == 0 && fdsArray[i] == listensock)else{// 处理普通sock的IO事件!if(fdsArray[i].revents & POLLIN){// 一定是一个合法的普通的IO类sock就绪了// read/recv读取即可// TODO bugchar buffer[1024];ssize_t s = recv(fdsArray[i].fd, buffer, sizeof(buffer), 0); // 不会阻塞if(s > 0){buffer[s] = 0;cout << "client[" << fdsArray[i].fd << "]# " << buffer << endl; }else if(s == 0){cout << "client[" << fdsArray[i].fd << "] quit, server close " << fdsArray[i].fd << endl;close(fdsArray[i].fd);fdsArray[i].fd = DFL; // 去除对该文件描述符的select事件监听fdsArray[i].events = 0;fdsArray[i].revents = 0;showArray(fdsArray, NUM);}else{cout << "client[" << fdsArray[i].fd << "] quit, server error " << fdsArray[i].fd << endl;close(fdsArray[i].fd);fdsArray[i].fd = DFL; // 去除对该文件描述符的select事件监听fdsArray[i].events = 0;fdsArray[i].revents = 0;showArray(fdsArray, NUM);}}}}
}// ./SelectServer 8080
// 只关心读事件
int main(int argc, char *argv[])
{if (argc != 2){usage(argv[0]);exit(1);}// 是一种类型,位图类型,能定义变量,那么就一定有大小,就一定有上限// fd_set fds; // fd_set是用位图表示多个fd的// cout << sizeof(fds) * 8 << endl;int listensock = Sock::Socket();Sock::Bind(listensock, atoi(argv[1]));Sock::Listen(listensock);for (int i = 0; i < NUM; i++){fdsArray[i].fd = DFL;fdsArray[i].events = 0;fdsArray[i].revents = 0;}fdsArray[0].fd = listensock;fdsArray[0].events = POLLIN;int timeout = -1;while (true){int n = poll(fdsArray, NUM, timeout);switch (n){case 0:cout << "time out ... : " << (unsigned long)time(nullptr) << endl;break;case -1:cerr << errno << " : " << strerror(errno) << endl;break;default:HandlerEvent(listensock);// 等待成功// 1. 刚启动的时候,只有一个fd,listensock// 2. server 运行的时候,sock才会慢慢变多// 3. select 使用位图,采用输出输出型参数的方式,来进行 内核<->用户 信息的传递, 每一次调用select,都需要对历史数据和sock进行重新设置!!!// 4. listensock,永远都要被设置进readfds中!// 5. select 就绪的时候,可能是listen 就绪,也可能是普通的IO sock就绪啦!!break;}}return 0;
}

三、poll方案多路转接的总结

poll方案的优点:
poll方案的多路转接不同于select方案的多路转接使用三个位图来表示三个fdset的方式,poll使用一个pollfd的指针来实现,这个指针其实是一个结构体数组。

pollfd结构体里包含了要监视的event和发送的event,不再使用select的那种输入输出采用同一个参数的方式,因此poll函数接口使用起来比select要简单方便。

除此之外,poll方案并没有最大的数量限制,pollfd这个结构体数组的元素个数是由我们用户自己决定的,它不像select那样采用位图结构,规定了最大数量限制就是1024。但是poll方案数量过大之后性能也是会下降的。

poll方案的缺点:
poll函数和select函数一样,poll函数返回后都需要轮询检测pollfd来获取就绪的文件描述符,当pollfd中监听的文件描述符数目增多时,性能也会下降。

每次调用poll函数都需要把大量的pollfd结构从用户态拷贝到内核态,这也会因为pollfd结构数组中元素个数过多时导致性能下降。

同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的文件描述符数量的增长,其效率也会线性下降。

相关文章:

Linux多路转接之poll

文章目录 一、poll的认识二、编写poll方案服务器三、poll方案多路转接的总结 一、poll的认识 多路转接技术是在不断更新进步的&#xff0c;一开始多路转接采用的是select方案&#xff0c;但是select方案存在的缺点比较多&#xff0c;所以在此基础上改进&#xff0c;产生了poll…...

Webpack打包流程

轻松了解Webpack 打包流程 Webpack是一个现代的JavaScript应用程序的静态模块打包器。它将多个JavaScript文件打包成一个或多个静态资源文件&#xff0c;以便在浏览器中加载。Webpack将应用程序视为一个依赖项图&#xff0c;其中包括应用程序的所有模块&#xff0c;然后通过该…...

React事件委托

React 事件委托&#xff08;Event Delegation&#xff09;是一种优化事件处理的技术&#xff0c;它通过将事件监听器添加到父级元素&#xff08;而不是子元素&#xff09;来实现。当事件触发时&#xff0c;事件会向上冒泡到父元素&#xff0c;然后在父元素上调用事件处理函数。…...

Notion——构建个人知识库

前言 使用Notion快三年了&#xff0c;它All in one的理念在使用以后确实深有体会&#xff0c;一直想找一个契机将这个软件分享给大家&#xff0c;这款笔记软件在网上已经有很多的教程了&#xff0c;所以在这里我主要想分享框架方面的内容给大家&#xff0c;特别对于学生党、研究…...

ModuleNotFoundError: No module named ‘Multiscaledeformableattention‘

在实现DINO Detection方法时&#xff0c;我们可能会遇到以上问题。因为在DeformableAttention模块&#xff0c;为了加速&#xff0c;需要自己去编译这个模块。 如果你的环境变量中能够找到cuda路径&#xff0c;使用正确的torch版本和cuda版本的话&#xff0c;这个问题很容易解…...

【数据结构】链表(C语言实现)

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c语言系列专栏&#xff1a;c语言之路重点知识整合 &#x…...

【2023程序员必看】大数据行业分析

1、政策重点扶持&#xff0c;市场前景广阔 2014年&#xff0c;大数据首次写入政府工作报告&#xff0c;大数据逐渐成为各级政府关注的热点。 2015年9月&#xff0c;国务院发布《促进大数据发展的行动纲要》&#xff0c;大数据正式上升至国家战略层面&#xff0c;十九大报告提…...

通达信SCTR强势股选股公式,根据六个技术指标打分

SCTR指标(StockCharts Technical Rank)的思路来源于著名技术分析师约翰墨菲&#xff0c;该指标根据长、中、短三个周期的六个关键技术指标对股票进行打分&#xff0c;根据得分对一组股票进行排名&#xff0c;从而可以识别出强势股。 与其他技术指标一样&#xff0c;SCTR的设计…...

SpringBoot+Token+Redis+Lua+自动续签极简分布式锁Token登录方案

前言 用SpringBoot做一个项目&#xff0c;都要写登录注册之类的方案 使用Cookie或Session的话&#xff0c;它是有状态的&#xff0c;不符合现代的技术 使用Security或者Shiro框架实现起来比较复杂&#xff0c;一般项目无需用那么复杂 使用JWT它虽然是无状态的&#xff0c;也可…...

多模态:MiniGPT-4

多模态&#xff1a;MiniGPT-4 IntroductionMethodlimitation参考 Introduction GPT-4具有很好的多模态能力&#xff0c;但是不开源。大模型最近发展的也十分迅速&#xff0c;大模型的涌现能力可以很好的迁移到各类任务&#xff0c;于是作者猜想这种能力可不可以应用到多模态模…...

5年时间里,自动化测试于我带来的意义,希望你也能早点知道

摘要&#xff1a;在我有限的软件测试经历里&#xff0c;曾有一段专职的自动化测试经历。 接触自动化 那时第一次上手自动化测试&#xff0c;团队里用的是Python&#xff0c;接口自动化测试的框架是requestsExcelJenkins&#xff0c;APP自动化测试的框架是Appium。 整个公司当…...

【MyBaits】SpringBoot整合MyBatis之动态SQL

目录 一、背景 二、if标签 三、trim标签 四、where标签 五、set标签 六、foreach标签 一、背景 如果我们要执行的SQL语句中不确定有哪些参数&#xff0c;此时我们如果使用传统的就必须列举所有的可能通过判断分支来解决这种问题&#xff0c;显示这是十分繁琐的。在Spring…...

涅槃重生,BitKeep如何闯出千万用户新起点

在全球&#xff0c;BitKeep钱包现在已经有超过千万用户在使用。 当我得知这个数据的时候&#xff0c;有些惊讶&#xff0c;也有点意料之中。关注BitKeep这几年&#xff0c;真心看得出这家公司的发展之迅速。还记得2018年他们推出第一个版本时&#xff0c;小而美&#xff0c;简洁…...

绝地求生 压枪python版

仅做学习交流&#xff0c;非盈利&#xff0c;侵联删&#xff08;狗头保命) 一、概述 1.1 效果 总的来说&#xff0c;这种方式是通过图像识别来完成的&#xff0c;不侵入游戏&#xff0c;不读取内存&#xff0c;安全不被检测。 1.2 前置知识 游戏中有各种不同的枪械&#x…...

麒麟操作V10SP1系统systemd目标单元

通过命令列出当前系统中所有可用的 systemd 目标单元。 用于被控制系统启动时运行哪些服务和进程&#xff0c;以及系统在运行过程中的行为。 rootkylin:~# systemctl list-units --typetargetUNIT LOAD ACTIVE SUB DESCRIPTION basic.target…...

python基于LBP+SVM开发构建基于fer2013数据集的人脸表情识别模型是种什么体验,让结果告诉你...

本身LBPSVM是比较经典的技术路线用来做图像识别、目标检测&#xff0c;没有什么特殊的地方 fer2013数据集在我之前的博文中也有详细的实践过&#xff0c;如下&#xff1a; 《fer2013人脸表情数据实践》 系统地基于CNN开发实现 《Python实现将人脸表情数据集fer2013转化为图像…...

antd——实现不分页的表格前端排序功能——基础积累

最近在写后台管理系统时&#xff0c;遇到一个需求&#xff0c;就是给表格中的某些字段添加排序功能。注意该表格是不分页的&#xff0c;因此排序可以只通过前端处理。 如下图所示&#xff1a; 在antd官网上是有关于表格排序的功能的。 对某一列数据进行排序&#xff0c;通过…...

案例11:Java超市管理系统设计与实现开题报告

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…...

@JsonAlias 和 @JsonProperty的使用

JsonAlias 和 JsonProperty 前言一、JsonAlias二、JsonProperty总结 前言 使用场景&#xff1a;主要运用于参数映射。 如&#xff1a;将admin_id 的值赋予adminId 常用于&#xff1a;接收第三方参数&#xff0c;并对参数进行驼峰化或别名。 一、JsonAlias 是在反序列化的时候…...

Grafana系列-统一展示-8-ElasticSearch日志快速搜索仪表板

系列文章 Grafana 系列文章 概述 我们是基于这篇文章: Grafana 系列文章&#xff08;十二&#xff09;&#xff1a;如何使用 Loki 创建一个用于搜索日志的 Grafana 仪表板, 创建一个类似的, 但是基于 ElasticSearch 的日志快速搜索仪表板. 最终完整效果如下: &#x1f4dd;…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

Linux中《基础IO》详细介绍

目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改&#xff0c;实现简单cat命令 输出信息到显示器&#xff0c;你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...

Python网页自动化Selenium中文文档

1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API&#xff0c;让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API&#xff0c;你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...

npm安装electron下载太慢,导致报错

npm安装electron下载太慢&#xff0c;导致报错 背景 想学习electron框架做个桌面应用&#xff0c;卡在了安装依赖&#xff08;无语了&#xff09;。。。一开始以为node版本或者npm版本太低问题&#xff0c;调整版本后还是报错。偶尔执行install命令后&#xff0c;可以开始下载…...