多路转接Poll

        在之前我们讲过select是最古老的多路转接方案,古老就意味着他不是很方便使用,他需要用户手动保存fd_set这个位图结构,来表示读写事件的关注与否或者就绪性。

        而且由于fd_set的大小是固定的,这就意味着他能管理的套接字文件描述符是有限的。针对这两个问题,人们研究出来了poll,他一方面不需要用户手动保存位图了,还能让poll管理的文件描述符是无限多的,只要你的内存足够大。

一、Poll的函数原型

参数说明:
  1. fds
    • 类型:struct pollfd *
    • 作用:指向 pollfd 结构体的数组,每个元素描述一个要监控的文件描述符及其关注的事件。正是由于这传的参数是一个结构体数组指针,所以理论上只要你的数组足够大,那么我poll能管理的文件描述符也就越多。
  2. nfds
    • 类型:nfds_t(通常是无符号整数)
    • 作用:数组 fds 中的结构体个数,即要监控的文件描述符数量。
  3. timeout
    • 类型:int
    • 作用:超时时间(毫秒)。
    • 这是一个纯粹的输入型参数,和之前的select不同。
      • timeout > 0:最多等待 timeout 毫秒。
      • timeout == 0:非阻塞模式,立即返回。
      • timeout < 0:无限等待,直到有事件发生。
返回值:
  • > 0:表示有事件发生,返回值为就绪的文件描述符数量。
  • == 0:超时,无任何事件发生。
  • < 0:发生错误,返回 -1 并设置 errno

二、Poll的第一个参数是如何做到不用手动保存的呢?

        可以看到pollfd结构体的成员是这样的,其中第一个成员表示的是文件描述符的值,而第二个第三个成员则是用户需要让内核监控哪些事件、内核返还给用户哪些事件已经就绪了。

        之前我们在使用select的时候,fd_set分为读、写、和异常,他们三个位图就管理了所有的文件描述符,所以造就了其复杂性。但是这里把文件描述符的值和事件分开了,一个pollfd就对应一个文件描述符及其关注的事件。从而让不同文件描述符不用相同的资源,而做到解耦。

三、使用poll的示例

        这个示例和select的大同小异,仅仅更改select为poll

#pragma once
#include <iostream>
#include "socket.hpp"
#include <memory>
#include<poll.h>
#include "InetAddr.hpp"using namespace socket_ns;class PollServer
{const static int gdefaultfd = -1;const static int gnum=1024;public:PollServer(uint16_t port): _port(port), _listensock(std::make_unique<TcpSocket>()), _timeout(1000){}~PollServer() {}void InitServer(){_listensock->BuildListenSocket(_port);for(int i=0;i<gnum;i++){_events[i].fd=gdefaultfd;_events[i].events=0;_events[i].revents=0;}//把listen添加进来_events[0].fd=_listensock->sockfd();_events[0].events=POLLIN;//对读事件关心}void Accepter(){// listen套接字得到一个新连接请求-----读事件就绪// 因为已经就绪了,就不会被阻塞了,即accept不会再等了InetAddr client;SockPtr sock = _listensock->Accepter(&client);if (sock->sockfd() > 0){LOG(DEBUG, "get a new link,client info %s:%d\n", client.Ip().c_str(), client.Port());// 处理(但是这里不能直接处理,如果客户端不发消息那我仍然阻塞了)// 那么如何得知fd底层的数据是否就绪了呢?仍然是select!这些fd都要由select管理起来// 所以select中的文件描述符会越来越多// 只需要将新获得的连接套接字放入到fd_array中即可bool flag = false;// 看辅助数组中有没有空余位置给新fd使用,有则插入for (int pos = 1; pos < gnum; pos++){if (_events[pos].fd == gdefaultfd){flag = true;//将新获得的套接字,加入到poll管理的pollfd数组中_events[pos].fd = sock->sockfd();_events[pos].events=POLLIN;_events[pos].revents=0;LOG(INFO, "add %d to fd_array success!\n", sock->sockfd());break;}}// 遍历完成发现是满的if (flag == false){LOG(WARNING, "Server is Full!\n");// 因为处理不了了,所以直接关闭刚刚获得到的连接的套接字::close(sock->sockfd());}}}void Handler_IO(int i){char buffer[1024];// 这里读就不会阻塞了,因为select已经等过了ssize_t n = ::recv(_events[i].fd, buffer, sizeof(buffer) - 1, 0);if (n > 0){buffer[n] = 0;std::cout << "client say#" << buffer << std::endl;// 回复的时候也需要用select找到就绪的,但任何一个sockfd被创建的时候,他的读写缓冲区一定是空的,我们之前关心读事件,是关心// 读缓冲区有没有数据,所以读天然就是不就绪的,但是写天然是就绪的//  std::string echo_str="[server echo info]";//  echo_str+=buffer;std::string content = "<html><body></h1>hello world</body></html>";std::string echo_str = "HTTP/1.0 200 OK\r\n";echo_str += "Content-Type: text/html\r\n";echo_str += "Cotent-Length:" + std::to_string(content.size()) + "\r\n\r\n";echo_str += content;::send(_events[i].fd, echo_str.c_str(), echo_str.size(), 0);}// 对方把连接关了else if (n == 0){LOG(INFO, "client quit...\n");// 把该文件描述符从fd_array中拿出来::close(_events[i].fd);_events[i].events=0;_events[i].revents=0;_events[i].fd = gdefaultfd;}else{LOG(ERROR, "recv error!\n");}}// 一定有大量的fd就绪,可能是普通sockfd套接字,也可能是linsten套接字void HandlerEvent(){//变量查看合法的fdfor(int i=0;i<gnum;i++){if(_events[i].fd==gdefaultfd){continue;}//合法的文件描述符,判断是否就绪int fd=_events[i].fd;short revents=_events[i].revents;if(revents&POLLIN){//读就绪//判断是listen套接字就绪还是普通文件就绪,进行任务派发if(fd==_listensock->sockfd()){Accepter();}else{Handler_IO(i);}}if(revents&POLLOUT){//写就绪}}}void Loop(){while (1){// 3.调用selectstruct timeval timeout = {3, 0};// 由于select是一个输入输出型参数,所以必须要有一个辅助数组来保存fd信息,用来重置参数int n = ::poll(_events,gnum,_timeout);switch (n){case 0:LOG(DEBUG, "time out\n");break;case -1:LOG(ERROR, "select error\n");break;default:// // 如果事件已经就绪了,但是我没有做处理,则底层会一直通知我,告诉我有文件描述符就绪了,所以下一次调用select就不会再判断了,直接通知LOG(INFO, "have event ready,n: %d\n", n);// 处理HandlerEvent();PrintDebug();break;}// sleep(1);}}void PrintDebug(){std::cout << "fd list:" << std::endl;for (int i = 0; i < gnum; i++){if (_events[i].fd=gdefaultfd){continue;}std::cout << _events[i].fd << " ";std::cout << std::endl;}}private:uint16_t _port;std::unique_ptr<Socket> _listensock;struct pollfd _events[gnum];int _timeout;
};

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

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

相关文章

C语言贪吃蛇实现

When the night gets dark,remember that the Sun is also a star. 当夜幕降临时&#xff0c;请记住太阳也是一颗星星。 ————《去月球海滩篇》 目录 文章目录 一、《贪吃蛇》游戏介绍 二、WIN32部分接口简单介绍 2.1 控制台窗口大小设置 2.2 命令行窗口的名称的变更 2…

基于深度学习的图片识别系统(下)

文章目录 前言1.任务描述2.模型搭建3.代码解释3.1模型加载3.2加载数据3.3模型权重的保存3.4学习率3.5过拟合3.6训练模型3.7调试检查 4.结果分析5. 完整代码结语 前言 书接上回&#xff0c;我们已经完成数据预处理部分的内容&#xff0c;后续仍需要对表格进行裁剪&#xff0c;此…

再学:区块链基础与合约初探 EVM与GAS机制

目录 1.区块链是什么 2.remix ​3.账户​ ​4.以太坊三种交易​ 5.EVM 6.以太坊客户端节点 ​7.Gas费用 8.区块链浏览器 1.区块链是什么 只需要检验根节点 Merkel根是否有更改&#xff0c;就不用检查每个交易是否有更改。方便很多。 2.remix 3.账户 如果交易失败的话&…

Java 中装饰者模式与策略模式在埋点系统中的应用

前言 在软件开发中&#xff0c;装饰者模式和策略模式是两种常用的设计模式&#xff0c;它们在特定的业务场景下能够发挥巨大的作用。本文将通过一个实际的埋点系统案例&#xff0c;探讨如何在 Java 中运用装饰者模式和策略模式&#xff0c;以及如何结合工厂方法模式来优化代码…

HCIP_NOTE03_网络组成

网络组成 LAN MAN WAN 园区网 企业或机构内部的网络,分大中小型 行业园:企业园网 校园网 政务园 商业园 三层交换机 数据大量交换的局域网内部,转发效率高,有简单的路由功能 路由器 进出口网络,适用于复杂的网络环境,选路需求 无线网 信号传输稳定性差---- 电磁波易受干…

简记_单片机硬件最小系统设计

以STM32为例&#xff1a; 一、电源 1.1、数字电源 IO电源&#xff1a;VDD、VSS&#xff1a;1.8~3.6V&#xff0c;常用3.3V&#xff0c;去耦电容1 x 10u N x 100n &#xff1b; 内核电源&#xff1a;内嵌的稳压器输出&#xff1a;1.2V&#xff0c;给内核、存储器、数字外设…

32.[前端开发-JavaScript基础]Day09-元素操作-window滚动-事件处理-事件委托

JavasScript事件处理 1 认识事件处理 认识事件(Event) 常见的事件列表 认识事件流 2 事件冒泡捕获 事件冒泡和事件捕获 事件捕获和冒泡的过程 3 事件对象event 事件对象 event常见的属性和方法 事件处理中的this 4 EventTarget使用 EventTarget类 5 事件委托模式 事件委托&am…

LeetCode hot 100 每日一题(15)——48.旋转图像

这是一道难度为中等的题目&#xff0c;让我们来看看题目描述&#xff1a; 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 提示…

图灵300题-21~40-笔记002

图灵300题 图灵面试题视频&#xff1a;https://www.bilibili.com/video/BV17z421B7rB?spm_id_from333.788.videopod.episodes&vd_sourcebe7914db0accdc2315623a7ad0709b85&p20。 本文是学习笔记&#xff0c;如果需要面试没有时间阅读原博文&#xff0c;可以快速浏览笔…

09_从经典论文入手Seq2Seq架构

Sequence to Sequence 架构 Paper链接 Sequence to Sequence Learning with Neural Networks B站课程ShusenWang 核心思想 关键的改进点 In this paper, we show that a straightforward application of the Long Short-Term Memory (LSTM) architecture [16] can solve …

大疆上云api介绍

概述 目前对于 DJI 无人机接入第三方云平台,主要是基于 MSDK 开发定制 App,然后自己定义私有上云通信协议连接到云平台中。这样对于核心业务是开发云平台,无人机只是其中一个接入硬件设备的开发者来说,重新基于 MSDK 开发 App 工作量大、成本高,同时还需要花很多精力在无人…

3、孪生网络/连体网络(Siamese Network)

目的&#xff1a; 用Siamese Network (孪生网络) 解决Few-shot learning (小样本学习)。 Siamese Network并不是Meta Learning最好的方法&#xff0c; 但是通过学习Siamese Network&#xff0c;非常有助于理解其他Meta Learning算法。 这里介绍了两种方法&#xff1a;Siame…

OpenCV图像拼接(7)根据权重图对源图像进行归一化处理函数normalizeUsingWeightMap()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::normalizeUsingWeightMap 是 OpenCV 中用于图像拼接细节处理的一个函数。它根据权重图对源图像进行归一化处理&#xff0c;通常用于…

卷积神经网络 - AlexNet各层详解

AlexNet的层次化设计&#xff0c;使得 AlexNet 能够逐层提取从简单边缘到复杂图形的特征&#xff0c;同时结合归一化、池化和 Dropout 技术&#xff0c;有效提升了训练速度和泛化能力&#xff0c;成为推动深度学习发展的重要里程碑。本文我们来理解AlexNet各层的参数设置以及对…

【设计模式】工厂模式

首先了解一下什么是工厂方法模式&#xff1f; 工厂方法模式&#xff08;Factory Method Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种方法来封装对象的创建逻辑。具体来说&#xff0c;它通过定义一个创建对象的接口&#xff08;即工厂方法&#xff09;&a…

centos 7 部署FTP 服务用shell 脚本搭建

#!/bin/bash# 检查是否以root身份运行脚本 if [ "$EUID" -ne 0 ]; thenecho "请以root身份运行此脚本。"exit 1 fi# 安装vsftpd yum install -y vsftpd# 启动vsftpd服务并设置开机自启 systemctl start vsftpd systemctl enable vsftpd# 配置防火墙以允许F…

基于Spring Boot的个性化商铺系统的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

AI(DeepSeek、ChatGPT)、Python、ArcGIS Pro多技术融合下的空间数据分析、建模与科研绘图及论文写作

人工智能&#xff08;AI&#xff09;与ArcGIS Pro的结合&#xff0c;为空间数据处理和分析开辟了前所未有的创新路径。AI通过强大的数据挖掘、深度学习及自动化能力&#xff0c;可高效处理海量、多源、异构的空间数据&#xff0c;极大提升了分析效率与决策支持能力。而ArcGIS P…

2025最新3个wordpress好用的主题

红色大气的wordpress企业主题&#xff0c;适合服务行业的公司搭建企业官方网站使用。是一款专为中小企业和个人开发者设计的WordPress主题&#xff0c;旨在提供专业的网站构建解决方案。 通过此WordPress主题&#xff0c;用户可以轻松创建和维护一个专业的企业网站&#xff0c…

Spring AI Alibaba AudioModel使用

一、AudioModel简介 1、AudioModel 当前&#xff0c;Spring AI Alibaba 支持以下两种通义语音模型的适配&#xff0c;分别是&#xff1a; 文本生成语音 SpeechModel&#xff0c;对应于 OpenAI 的 Text-To-Speech (TTS) API录音文件生成文字 DashScopeAudioTranscriptionMode…