【计算机网络】IO多路转接之poll
文章目录
- 一、poll函数接口
- 二、socket就绪条件
- 三、poll的优点
- 四、poll的缺点
- 五、poll使用案例--只读取数据的server服务器
- 1.err.hpp
- 2.log.hpp
- 3.sock.hpp
- 4.pollServer.hpp
- 5.main.cc
一、poll函数接口
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
// pollfd结构
struct pollfd {int fd; /* file descriptor */short events; /* requested events */short revents; /* returned events */
};
参数说明
fds是一个poll函数监听的结构列表. 每一个元素中, 包含了三部分内容: 文件描述符, 监听的事件集合, 返回的事件集合.
nfds表示fds数组的长度.
timeout表示poll函数的超时时间, 单位是毫秒(ms)
时间单位:ms
1.>0:在timeout以内,阻塞,否则非阻塞返回一次
2.=0:非阻塞等待
3.<0:阻塞等待
events和revents的取值:

用户 -> 内核 :要帮我关心一下fd。输入看 :fd + events
内核告诉用户:你要关心fd上面的events中有哪些事件已经就绪了。输出时看:fd + revents
这样达到了输入和输出分离,poll不需要对参数进行重新设定,以及解决了select等待fd有上限的问题
返回结果
返回值小于0, 表示出错;
返回值等于0, 表示poll函数等待超时;
返回值大于0, 表示poll由于监听的文件描述符就绪而返回.
二、socket就绪条件
读就绪
socket内核中, 接收缓冲区中的字节数, 大于等于低水位标记SO_RCVLOWAT. 此时可以无阻塞的读该文件描述符, 并且返回值大于0;
socket TCP通信中, 对端关闭连接, 此时对该socket读, 则返回0;
监听的socket上有新的连接请求;
socket上有未处理的错误;
写就绪
socket内核中, 发送缓冲区中的可用字节数(发送缓冲区的空闲位置大小), 大于等于低水位标记
SO_SNDLOWAT, 此时可以无阻塞的写, 并且返回值大于0;
socket的写操作被关闭(close或者shutdown). 对一个写操作被关闭的socket进行写操作, 会触发SIGPIPE信号;
socket使用非阻塞connect连接成功或失败之后;
socket上有未读取的错误;
异常就绪
socket上收到带外数据. 关于带外数据, 和TCP紧急模式相关(TCP协议头中, 有一个紧急指针的字段),
三、poll的优点
不同与select使用三个位图来表示三个fdset的方式,poll使用一个pollfd的指针实现.
pollfd结构包含了要监视的event和发生的event,不再使用select“参数-值”传递的方式. 接口使用比select更方便.
poll并没有最大数量限制 (但是数量过大后性能也是会下降)
四、poll的缺点
poll中监听的文件描述符数目增多时,和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符.
每次调用poll都需要把大量的pollfd结构从用户态拷贝到内核中.
同时连接的大量客户端在一时刻可能只有很少的处于就绪状态, 因此随着监视的描述符数量的增长, 其效率也会线性下降.
五、poll使用案例–只读取数据的server服务器
1.err.hpp
#pragma onceenum
{USAGE_ERR = 1,SOCKET_ERR,BIND_ERR,LISTEN_ERR
};
2.log.hpp
#pragma once#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <stdarg.h>#define NORMAL 0
#define DEBUG 1
#define WARNING 2
#define ERROR 3
#define FATAL 4#define LOG_NORMAL "./log.txt"
#define LOG_ERR "./err.txt"#define NUM 1024const char *to_levelstr(int level)
{switch (level){case DEBUG:return "DEBUG";case NORMAL:return "NORMAL";case WARNING:return "WARNING";case ERROR:return "ERROR";case FATAL:return "FATAL";default:return nullptr;}
}void LogMessage(int level, const char *format, ...)
{// [日志等级] [时间戳/时间] [pid] [messge]char logprofix[NUM];snprintf(logprofix, sizeof logprofix, "[%s][%ld][pid:%d]", to_levelstr(level), (long int)time(nullptr), getpid());char logcontent[NUM];va_list arg;va_start(arg, format);vsnprintf(logcontent, sizeof logcontent, format, arg);std::cout << logprofix << logcontent << std::endl;FILE *log = fopen(LOG_NORMAL, "a");FILE *error = fopen(LOG_ERR, "a");if (log && error){FILE *cur = nullptr;if (level == DEBUG || level == NORMAL || level == WARNING)cur = log;if (level == ERROR || level == FATAL)cur = error;if (cur)fprintf(cur, "%s%s\n", logprofix, logcontent);fclose(log);fclose(error);}
}
3.sock.hpp
#pragma once#include <iostream>
#include <cstring>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#include "log.hpp"
#include "err.hpp"class Sock
{static const int backlog = 32;public:// 1. 创建socket文件套接字对象static int Socket(){int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock < 0){LogMessage(FATAL, "create socket error");exit(SOCKET_ERR);}LogMessage(NORMAL, "create socket success:%d", sock);int opt = 1;setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof opt);return sock;}// 2.bind自己的网络信息static void Bind(int sock, const uint16_t &port){struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;local.sin_port = htons(port);local.sin_addr.s_addr = INADDR_ANY;int n = bind(sock, (struct sockaddr *)&local, sizeof local);if (n < 0){LogMessage(FATAL, "socket bind error");exit(BIND_ERR);}LogMessage(NORMAL, "socket bind success");}// 3. 设置socket 为监听状态static void Listen(int sock){int n = listen(sock, backlog);if (n < 0){LogMessage(FATAL, "socket listen error");exit(LISTEN_ERR);}LogMessage(NORMAL, "socket listen success");}static int Accept(int listensock, std::string *clientip, uint16_t *clientport){struct sockaddr_in peer;memset(&peer, 0, sizeof peer);socklen_t len = sizeof(peer);int sock = accept(listensock, (struct sockaddr *)&peer, &len);if (sock < 0){LogMessage(ERROR, "socket accept error,next");}else{LogMessage(NORMAL, "accept a new link success, get new sock: %d", sock);*clientip = inet_ntoa(peer.sin_addr);*clientport = ntohs(peer.sin_port);}return sock;}
};
4.pollServer.hpp
#pragma once#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <string>
#include <functional>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <poll.h>#include "sock.hpp"
#include "log.hpp"
#include "err.h"namespace poll_ns
{const static int defaultport = 8080;const static int num = 2048;const static int defaultfd = -1;typedef std::function<std::string(const std::string &)> func_t;class pollServer{public:pollServer(const func_t &func, const uint16_t &port = defaultport): _port(port), _func(func), _listensock(-1), _rfds(nullptr){}void initServer(){_listensock = Sock::Socket();Sock::Bind(_listensock, _port);Sock::Listen(_listensock);_rfds = new struct pollfd[num];for (int i = 0; i < num; i++)ResetItem(i);_rfds[0].fd = _listensock;_rfds[0].events = POLLIN;_rfds[0].revents = 0;}void ResetItem(int pos){_rfds[pos].fd = defaultfd;_rfds[pos].events = 0;_rfds[pos].revents = 0;}void Print(){std::cout << "fd list: ";for (int i = 0; i < num; i++){if (_rfds[i].fd != defaultfd){std::cout << _rfds[i].fd << " ";}}}void Accepter(int listensock){std::string clientip;uint16_t clientport;int sock = Sock::Accept(listensock, &clientip, &clientport);if (sock < 0)return;LogMessage(NORMAL, "accept success[%s:%d]", clientip.c_str(), clientport);int i = 0;for (; i < num; i++){if (_rfds[i].fd == defaultfd)continue;elsebreak;}if (i == num){LogMessage(WARNING, "server is full,please wait");close(sock);}else{_rfds[i].fd = sock;_rfds[i].events = POLLIN;_rfds[i].revents = 0;}Print();}void Recver(int pos){// 1. 读取requestchar buffer[1024];ssize_t s = recv(_rfds[pos].fd, buffer, sizeof(buffer) - 1, 0); // 这里在进行读取的时候,会不会被阻塞?1, 0if (s > 0){buffer[s] = 0;LogMessage(NORMAL, "client# %s", buffer);}else if (s == 0){close(_rfds[pos].fd);ResetItem(pos);LogMessage(NORMAL, "client quit");return;}else{close(_rfds[pos].fd);ResetItem(pos);LogMessage(ERROR, "client error:%s", strerror(errno));return;}// 2. 处理requeststd::string response = _func(buffer);// 3. 返回responsewrite(_rfds[pos].fd, response.c_str(), response.size());}void HandlerEvent(){for (int i = 0; i < num; i++){// 过滤掉非法的fdif (_rfds[i].fd == defaultfd)continue;if (!(_rfds[i].events & POLLIN))continue;if (_rfds[i].fd == _listensock && (_rfds[i].events & POLLIN))Accepter(_listensock);else if (_rfds[i].events & POLLIN)Recver(i);else{}}}void start(){for (;;){int timeout = -1;int n = poll(_rfds, num, timeout);switch (n){case 0:LogMessage(NORMAL, "timeout...");break;case -1:LogMessage(WARNING, "select error,code: %d, err string: %s", errno, strerror(errno));break;default:// 说明有事件就绪了,目前只有一个监听事件就绪了LogMessage(NORMAL, "have event ready!");HandlerEvent();break;}}}~pollServer(){if (_listensock > 0)close(_listensock);if (_rfds)delete[] _rfds;}private:int _port;int _listensock;struct pollfd *_rfds;func_t _func;};
}
5.main.cc
#include "pollServer.hpp"
#include "err.hpp"
#include <memory>using namespace std;
using namespace poll_ns;static void Usage(const string proc)
{std::cerr << "Usage:\n\t" << proc << " port\n\n";
}string transaction(const string &request)
{return "pollServer# " + request;
}int main(int argc, char *argv[])
{// if (argc != 2)// {// Usage(argv[0]);// exit(USAGE_ERR);// }std::unique_ptr<pollServer> svr(new pollServer(transaction));svr->initServer();svr->start();return 0;
}
相关文章:
【计算机网络】IO多路转接之poll
文章目录 一、poll函数接口二、socket就绪条件三、poll的优点四、poll的缺点五、poll使用案例--只读取数据的server服务器1.err.hpp2.log.hpp3.sock.hpp4.pollServer.hpp5.main.cc 一、poll函数接口 #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int t…...
性能比较:in和exists
当在Hive SQL中使用NOT IN和NOT EXISTS时,性能差异主要取决于底层数据的组织方式、数据量大小、索引的使用情况以及具体查询的复杂程度。下面是对这两种方法的性能分析: 1. NOT IN:- 工作原理:NOT IN子查询会逐个比较主查询中的值…...
【Java设计模式】五、建造者模式
文章目录 1、建造者模式2、案例:共享单车的创建3、其他用途 1、建造者模式 某个对象的构建复杂将复杂的对象的创建 和 属性赋值所分离,使得同样的构建过程可以创建不同的表示建造的过程和细节调用者不需要知道,只需要通过构建者去进行操作 …...
nginx代理minio教程 避坑过的教程 避开SignatureDoesNotMatch
本次教程使用的是单机minio进行演示,集群minio也和这个差不多。 按照这个教程,可以避开nginx代理minio之后,只能访问文件,但是通过预签名url上传文件就会报SignatureDoesNotMatch的坑 暂定如下: 你已经下载好miniom…...
Linux进程详细介绍
文章目录 Linux进程1、计算机体系结构和操作系统管理1.1、计算机体系结构 -- 硬件1.2、操作系统(Operator System) -- 软件 2、进程2.1、进程基本概念2.2、进程标识符2.2.1、获取当前进程标识符和当前进程的父进程标识符2.2.2、通过系统调用创建进程 -- …...
2024年3月产品认证基础考试简答题及答案
产品认证基础 46.产品认证的工厂检查有哪几种路线?各有什么优缺点? 答案:两种常用的检查路线: 1.按照要素或过程检查 按照认证规则规定的工厂应满足的要素要求(包括质量保证能力要求),结合部…...
嵌入式蓝桥杯做题总结
第十二届省赛 按键代码 ——自认为比较巧妙,定时器3被设置为10ms进入一次中断,代替了HAL_Delay(10)的方法消抖; 运用状态机机思想实现检测多个按键检测——且分为两个状态,其中一个状态PB1和PB2的按键不…...
Spring Boot 常用注解大全
以下是Spring Boot中常用的注解及其详细解释以及相应的代码示例: SpringBootApplication: 这个注解用于标识一个Spring Boot应用的主类。它整合了 Configuration,EnableAutoConfiguration 和 ComponentScan。 SpringBootApplication public class Demo…...
(MATLAB)第十二章-数列与极限
目录 12.1 数列 12.1.1 数列求和 1. 累计求和函数sum() 2. 忽略NaN累计求和函数 nansum() 3. 求此元素位置之前的元素和函数cumsum() 4. 求梯形累计和函数cumtrapz() 12.1.2 数列求积 1. 元素连续相乘函数 prod() 2. 求累计积函数 cumprod() 3. 阶乘函数 ffactorial(n…...
OJ输入问题+准备
写在之前: 发现题目输入是这样的: 我的问题:如何通过空格分割这些输入的字符串并分别保存!!(C语言scanf好解决一点但我选择C....) C引入了ostringstream、istringstream、stringstream这三个类…...
软考高级:主动攻击和被动攻击概念和例题
作者:明明如月学长, CSDN 博客专家,大厂高级 Java 工程师,《性能优化方法论》作者、《解锁大厂思维:剖析《阿里巴巴Java开发手册》》、《再学经典:《Effective Java》独家解析》专栏作者。 热门文章推荐&am…...
cuda python torch 虚拟环境配置
以下是Pytorch和CUDA对应的版本 以下是Pytorch和Python对应的版本 检查cuda与Python版本是否匹配 import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.empty(3,4,devicecuda))cuda 删除cuda conda uninstall cudatoolkit --forceconda u…...
激光炸弹 刷题笔记
前置知识 二维前缀和 子矩阵的和 刷题笔记 {二维前缀和}-CSDN博客 思路 参考二维前缀和 将子矩阵的和 做成动态矩阵 一个个矩阵搜索 符合要求边长 矩阵中的元素和最大值 将x1,y1用i-k,j-k表示即可 x2,y2用i,j表示 代码 #include<iostream> #include<…...
Vue3学习记录(三)--- 组合式API之生命周期和模板引用
一、生命周期 1、简介 生命周期,指的是一个 Vue 实例从创建到销毁的完整阶段,强调的是一个时间段。 生命周期钩子函数,指的是 Vue 实例提供的内置函数,函数的参数为一个回调函数。这些钩子函数会在实例生命周期的某些固定…...
Batch Normalization和Layer Normalization和Group normalization
文章目录 前言一、Group normalization二、批量规范化(Batch Normalization)三、层规范化(Layer Normalization) 前言 批量规范化和层规范化在神经网络中的每个批次或每个层上进行规范化,而GroupNorm将特征分成多个组,并在每个组内…...
命名实体识别NER(综合代码示例)
一、命名实体识别发展方向 二、中文数据集 CCKS2017开放的中文的电子病例测评相关的数据。 评测任务一:https://biendata.com/competition/CCKS2017_1/ 评测任务二:https://biendata.com/competition/CCKS2017_2/ CCKS2018开放的音乐领域的实体识别任务…...
关于jQuery日历插件:daterangepicker
关于options singleDatePicker: false 双日历,true 单日历 timePicker:false 不显示时分秒,true 显示时分秒 timePickerIncreament:1 默认值 {singleDatePicker : false, //是否显示单日历框 dateLimit : { days : 30 }, //起…...
【贪心算法】最大子序和
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组是数组中的一个连续部分。 示例 1: 输入:nums [-2,1,-3,4,-1,2,1,-5,4] 输出:6…...
爬虫逆向网站案例
一、相关网页 东方财富人气排行榜 二、查找url 三、寻找curl并复制 四、打开Convert curl commands to code (curlconverter.com) 五、修改并执行代码 import requestscookies {st_si: 73974981954644,st_pvi: 39724919122964,st_sp: 2024-03-05%2018%3A27%3A22,st_inirUrl:…...
蓝桥杯复习之前缀和
题目链接:https://www.luogu.com.cn/problem/P8649 思路: 看到区间和,第一反应肯定是前缀和,我们求出前缀和后对前缀和数组每一个值模k,然后对一个数组的值查看前面有几个相同的,举个例子:…...
告别GPS模块!用IRIG-B码为你的工业设备打造超高性价比的10ns同步时钟源
工业级10ns同步时钟方案:IRIG-B解码模块的实战应用指南 在工业自动化、电力系统和精密测试测量领域,时间同步精度往往直接关系到系统运行的可靠性与数据采集的准确性。传统GPS/北斗模块虽然普及,却面临着信号覆盖受限、设备成本高昂以及潜在安…...
JSP 语法详解
JSP 语法详解 引言 JSP(JavaServer Pages)是一种动态网页技术,它允许开发者在网页中嵌入Java代码,以实现与数据库的交互和动态内容生成。JSP语法简洁明了,易于学习和使用。本文将详细介绍JSP的语法结构,帮助读者更好地理解和应用JSP技术。 JSP基本语法 1. JSP页面结构…...
DLSS Swapper深度解析:游戏性能优化实战指南
DLSS Swapper深度解析:游戏性能优化实战指南 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper DLSS Swapper作为一款开源游戏性能优化工具,专为解决PC玩家面临的DLSS版本管理难题而生。在3A游戏对…...
Win11Debloat:让Windows系统重获新生的一站式自动化优化方案
Win11Debloat:让Windows系统重获新生的一站式自动化优化方案 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to declutter …...
运维系列【仅供参考】:【Docker】容器生命周期管理:从优雅停止到高效清理的实战技巧
【Docker】容器生命周期管理:从优雅停止到高效清理的实战技巧 【Docker】容器生命周期管理:从优雅停止到高效清理的实战技巧 摘要 1. 为什么需要关注容器生命周期管理? 2. 停止容器的艺术:从温柔到强硬 2.1 优雅停止的正确姿势 2.2 何时该用强制终止 2.3 暂停与恢复的妙用 …...
Acetic Acid-PEG-OPSS,分子链两端分别带有吡啶基二硫化物和乙酸基团
一.名称英文名称:AA-PEG-OPSS,Acetic Acid-PEG-OPSS,OPSS-PEG-AA,OPSS-PEG-Acetic Acid中文名称:乙酸聚乙二醇二巯基吡啶,乙酸PEG二巯基吡啶分子量:1k,2k,3.4k࿰…...
微生物网络分析参数配置与结果验证:microeco中SpiecEasi的进阶应用指南
微生物网络分析参数配置与结果验证:microeco中SpiecEasi的进阶应用指南 【免费下载链接】microeco An R package for data analysis in microbial community ecology 项目地址: https://gitcode.com/gh_mirrors/mi/microeco 在微生物生态学研究中,…...
快速验证c盘清理方案,用快马平台十分钟搭建原型工具
最近电脑C盘总是爆满,系统频繁弹窗提示空间不足,严重影响工作效率。作为一个非专业开发者,我尝试用InsCode(快马)平台快速搭建了一个C盘清理工具原型,整个过程比想象中简单许多。这里分享我的实现思路和具体操作步骤,或…...
开源音乐解锁工具:浏览器端全平台音频解密解决方案
开源音乐解锁工具:浏览器端全平台音频解密解决方案 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目地址: https://…...
OpenCascade实战:TopoDS_Shape数据结构的高效遍历与优化策略
1. TopoDS_Shape数据结构基础解析 在OpenCascade中,TopoDS_Shape是构建三维模型的基石。这个看似简单的类实际上包含了三个关键数据成员:myTShape、myLocation和myOrient。理解这三个字段的运作机制,是高效操作模型的前提。 myTShape是一个智…...
