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

Linux中的epoll简单使用案例

I/O 多路复用允许一个进程或线程同时监控多个网络 sockets 的状态。它通过单个系统调用(select)来检查多个 sockets 是否有数据可读、可写或是否有异常。Linux 提供了多种 I/O 复用技术,包括上面提到的 select、以及 poll、epoll。

创建epoll epoll_create

int epoll_fd = epoll_create(1);
if (epoll_fd == -1) {perror("epoll_create1 failed");close(server_fd);return 1;
}

epoll_create创建一个 epoll 实例,并返回一个文件描述符,该文件描述符用于后续的 epoll 操作,如 epoll_ctl 和 epoll_wait,epoll_create参数是一个正整数,用于提示内核该 epoll 实例将监控的文件描述符数量。从 Linux 2.6.8 开始,这个参数被忽略,但必须大于零。

监听事件 epoll_ctl

epoll_event event{};
event.events = EPOLLIN;
event.data.fd = server_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1) {perror("epoll_ctl failed");close(server_fd);close(epoll_fd);return 1;
}

创建epoll对象后,可以用epoll_ctl添加或删除所要监听的socket,并设置相应的监听事件。下面是函数原型

/* Manipulate an epoll instance "epfd". Returns 0 in case of success,-1 in case of error ( the "errno" variable will contain thespecific error code ) The "op" parameter is one of the EPOLL_CTL_*constants defined above. The "fd" parameter is the target of theoperation. The "event" parameter describes which events the calleris interested in and any associated user data.  */
extern int epoll_ctl (int __epfd, int __op, int __fd,struct epoll_event *__event) __THROW;
  • epfd:epoll句柄,由epoll_create创建。
  • op:操作类型,可以是EPOLL_CTL_ADD注册新的fd到epfd中、EPOLL_CTL_MOD修改已经注册的fd的监听事件、EPOLL_CTL_DEL从epfd中删除一个fd。
  • fd:被监听的文件描述符。
  • event:指向epoll_event结构体的指针,用于描述监听事件和事件附加数据。
    下面是epoll_event的具体实现
struct epoll_event{uint32_t events;    //Epoll 事件epoll_data_t data;  //用户数据
}

events用于指定监听的事件

  • EPOLLIN 表示文件描述符可读
  • EPOLLOUT 表示文件描述符可写
  • EPOLLET 表示使用边缘触发(Edge-Triggered)模式,而不是默认的水平触发(Level-Triggered)模式。
  • 水平触发(LT):当一个文件描述符处于就绪状态时,它会持续不断地向程序发送通知,直到该文件描述符不再处于就绪状态。例如,当一个套接字有数据可读时,epoll会一直通知程序进行读取操作,直到所有数据都被读取完毕。这种模式下,程序可以多次读取数据,无需关心是否一次性读取所有数据。
    适用于对性能要求不高或开发难度优先考虑的场景。例如,小型网络应用程序或简单的I/O操作。
  • 边缘触发(ET):只有当一个文件描述符的状态发生变化时,才会触发一次通知。例如,当一个套接字有数据可读时,epoll只会通知一次,之后需要程序一次性读取所有数据。如果程序没有读取完所有数据,epoll不会再次通知,直到该套接字再次有新的数据可读。
    适用于高并发、大数据量传输等对性能要求较高的场景。例如,大型网络服务器、高性能计算等。
    data成员用于存储用户数据,其类型epoll_data_t的定义如下:
typedef union epoll_data
{void *ptr;int fd;uint32_t u32;uint64_t u64;
} epoll_data_t;

epoll_data_t是一个共用体,其4个成员中使用最多的是fd,它指定事件所从属的目标文件描述符。ptr成员可以用来指定与fd相关的用户数据。但由于epoll_data_t是一个共用体,我们不能同时使用其ptr成员和fd成员,因此,如果要将文件描述符和用户数据关联起来,以实现快速的数据访问,只能放弃使用epoll_data_t的fd成员,而在ptr指向的用户数据中包含fd。

epoll_wait

它会等待一组文件描述符上的事件,阻塞等待注册的事件发生,返回事件的数目

// 用于设置最大事件量
epoll_event events[MAX_EVENTS];
// epoll_wait会一直阻塞只有有事件发送
int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (num_events == -1) {perror("epoll_wait failed");break;
}

其原型如下:

/* Wait for events on an epoll instance "epfd". Returns the number oftriggered events returned in "events" buffer. Or -1 in case oferror with the "errno" variable set to the specific error code. The"events" parameter is a buffer that will contain triggeredevents. The "maxevents" is the maximum number of events to bereturned ( usually size of "events" ). The "timeout" parameterspecifies the maximum wait time in milliseconds (-1 == infinite).This function is a cancellation point and therefore not marked with__THROW.  */
extern int epoll_wait (int __epfd, struct epoll_event *__events,int __maxevents, int __timeout);
  • epfd :epoll_create()的返回值;
  • events: 用来记录被触发的events(结构参考epoll_ctl),其大小受制于maxevents
  • maxevents: 设定最多监听多少个事件,必须大于0,一般设定为65535
  • timeout:在函数调用中阻塞时间上限,单位是ms
    • timeout = -1:表示调用将一直阻塞,直到有文件描述符进入ready状态或者捕获到信号才返回;
    • timeout = 0:用于非阻塞检测是否有描述符处于ready状态,不管结果怎么样,调用都立即返回;
    • timeout > 0:表示调用将最多持续timeout时间,如果期间有检测对象变为ready状态或者捕获到信号则返回,否则直到超时。
      成功时返回就绪的文件描述符个数,并且将用户详细放入epoll_event数组中
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <iostream>#define BUFFER_SIZE 1024
#define MAX_EVENTS 65535// 设置文件描述符为非阻塞模式
int set_nonblocking(int fd) {int flags = fcntl(fd, F_GETFL, 0);if (flags == -1) return -1;return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}int main(){int server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd == -1) {std::cerr << "socket error" << std::endl;return 1;}// 设置地址重用int opt = 1;if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1){std::cerr << "setsockopt error" << std::endl;return 1;}// 绑定地址和端口sockaddr_in address{};address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(12355);if (bind(server_fd, (sockaddr*)&address, sizeof(address)) < 0) {perror("bind failed");close(server_fd);return 1;}// 开始监听if (listen(server_fd, SOMAXCONN) < 0) {perror("listen failed");close(server_fd);return 1;}std::cout << "Server is listening on port 12355..." << std::endl;// 创建epoll实例int epoll_fd = epoll_create(1);if (epoll_fd == -1) {perror("epoll_create1 failed");close(server_fd);return 1;}// 添加服务器套接字到epollepoll_event event{};event.events = EPOLLIN;event.data.fd = server_fd;if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1) {perror("epoll_ctl failed");close(server_fd);close(epoll_fd);return 1;}// 用于设置最大事件量epoll_event events[MAX_EVENTS];while (true) {// 事件循环// epoll_wait会一直阻塞只有有事件发送int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);if (num_events == -1) {perror("epoll_wait failed");break;}for (int i = 0; i < num_events; ++i) {// 处理新连接if (events[i].data.fd == server_fd) {sockaddr_in client_addr{};socklen_t client_len = sizeof(client_addr);int client_fd = accept(server_fd, (sockaddr*)&client_addr, &client_len);if (client_fd == -1) {perror("accept failed");continue;}// 设置为非阻塞模式set_nonblocking(client_fd);// 添加客户端到epollepoll_event client_event{};client_event.events = EPOLLIN | EPOLLET; // 边缘触发模式client_event.data.fd = client_fd;if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &client_event) == -1) {perror("epoll_ctl client add failed");close(client_fd);continue;}std::cout << "New connection from: " << inet_ntoa(client_addr.sin_addr) << ":"<< ntohs(client_addr.sin_port) << std::endl;} else {// 处理客户端数据int client_fd = events[i].data.fd;char buffer[BUFFER_SIZE];ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE);if (bytes_read <= 0) {// 连接关闭或错误if (bytes_read == 0 || (bytes_read == -1 && errno != EAGAIN)) {std::cout << "Connection closed" << std::endl;epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);close(client_fd);}continue;}// 简单回显处理buffer[bytes_read] = '\0';std::cout << "Received: " << buffer;write(client_fd, buffer, bytes_read);}}}close(server_fd);close(epoll_fd);return 0;
}

相关文章:

Linux中的epoll简单使用案例

I/O 多路复用允许一个进程或线程同时监控多个网络 sockets 的状态。它通过单个系统调用&#xff08;select&#xff09;来检查多个 sockets 是否有数据可读、可写或是否有异常。Linux 提供了多种 I/O 复用技术&#xff0c;包括上面提到的 select、以及 poll、epoll。 创建epol…...

ASP4644四通道降压稳压器的工业高效电源管理方案

ASP4644工业级型号&#xff08;ASP4644I6B&#xff09;是一款专为工业场景设计的四通道降压稳压器&#xff0c;支持-40C至85C工作温度。其核心特性包括&#xff1a; 宽输入电压范围&#xff1a;4V–14V&#xff0c;适配工业现场多变的电源环境。 高负载能力&#xff1a;单通道…...

kali破解Pdf/execl/word

一、准备工作 1.工具安装 Kali Linux 内置部分工具&#xff0c;需补充安装以下工具&#xff1a; sudo apt update sudo apt install pdfcrack hashcat john -y git clone https://github.com/magnumripper/JohnTheRipper # 更新版John 2.字典准备 常用字典&#xff1a;Kal…...

宇树科技纯技能要求总结

一、嵌入式开发与硬件设计 核心技能 嵌入式开发&#xff1a; 精通C/C&#xff0c;熟悉STM32、ARM开发熟悉Linux BSP开发及驱动框架&#xff08;SPI/UART/USB/FLASH/Camera/GPS/LCD&#xff09;掌握主流平台&#xff08;英伟达、全志、瑞芯微等&#xff09; 硬件设计&#xff1a…...

RabbitMq C++客户端的使用

1.RabbitMq介绍 RabbitMQ 是一款开源的消息队列中间件&#xff0c;基于 AMQP&#xff08;高级消息队列协议&#xff09;实现&#xff0c;支持多种编程语言和平台。以下是其核心特点和介绍&#xff1a; 核心特点 多语言支持 提供 Java、Python、C#、Go、JavaScript 等语言的客…...

用通义大模型写爬虫程序,汇总各科成绩

需求&#xff1a;根据各科网址&#xff0c;输入学号、姓名查询成绩。 中间反反复复很多次&#xff0c;本文只记下重点的几次和大模型的沟通历史。 输入界面 查询界面 round0&#xff08;最初的问题&#xff09; 请在windows下&#xff0c;使用python的selenium库&#xff0…...

电商项目Ts版本

文章目录 项目地址一、环境安装1.1 配置作为导入1.2 文件目录 二、路由2.1 publicRoutes 项目地址 教程作者&#xff1a;教程地址&#xff1a; 代码仓库地址&#xff1a; 所用到的框架和插件&#xff1a; dbt airflow一、环境安装 1.1 配置作为导入 vite.config.ts impor…...

HarmonyOS Next中的弹出框使用

HarmonyOS Next弹出框概述及分类 弹出框是一种模态窗口&#xff0c;通常用于在保持当前上下文环境的同时&#xff0c;临时展示用户需关注的信息或待处理的操作。用户需在模态弹出框内完成相关交互任务之后&#xff0c;才能退出模态模式。弹出框可以不与任何组件绑定&#xff0…...

C++实现的数据结构示例,涵盖链表、数组、树和图

使用C实现的数据结构示例&#xff0c;涵盖链表、数组、树和图的基本操作&#xff1a; 链表&#xff08;单向链表&#xff09; #include <iostream> using namespace std;struct Node {int data;Node* next;Node(int val) : data(val), next(nullptr) {} };class Linked…...

FPGA中级项目4——DDS实现

FPGA中级项目4——DDS实现 DDS简介 DDS&#xff08;直接数字频率合成器&#xff0c;Direct Digital Frequency Synthesis&#xff09;是一种基于数字信号处理技术的频率合成方法&#xff0c;广泛应用于通信、雷达、仪器仪表等领域。在 FPGA中实现 DDS 具有灵活性高、集成度强、…...

深度学习-149-langchain之如何不使用with_structured_output()从模型中返回结构化数据

文章目录 1 不使用with_structured_output()方法1.1 问题背景1.2 输出解析器1.3 远程deepseek大模型API2 基于提示词2.1 直接使用提示词2.2 少样本提示词3 直接提示和解析模型输出3.1 使用PydanticOutputParser3.1.1 构建解析器3.1.2 构建提示模板3.1.3 调用大模型3.1.4 调用链…...

STM32 DAC详解:从原理到实战输出正弦波

目录 一、DAC基础原理1.1 DAC的作用与特性1.2 DAC功能框图解析 二、DAC配置步骤2.1 硬件配置2.2 初始化结构体详解 三、DAC数据输出与波形生成3.1 数据格式与电压计算3.2 正弦波生成实战3.2.1 生成正弦波数组3.2.2 配置DMA传输3.2.3 定时器触发配置 四、常见问题与优化建议4.1 …...

深度学习框架PyTorch——从入门到精通(5)构建神经网络

构建神经网络 获取训练设备定义类模型层nn.Flattennn.Linearnn.ReLUnn.Sequentialnn.Softmax 模型参数补充说明argmax 神经网络是由一些层或者模块组成的&#xff0c;这些层和模块会对数据进行各种操作。 在 PyTorch 里&#xff0c;torch.nn 这个命名空间提供了你搭建自己神经网…...

基于PyQt5与Open3D的轻量化BIM工具开发指南(下)‌

‌基于PyQt5与Open3D的轻量化BIM工具开发指南&#xff08;下&#xff09;‌ ‌——参数化建模、数据导出与性能优化‌ 【跳转】基于PyQt5与Open3D的轻量化BIM工具开发指南&#xff08;上&#xff09;‌ ‌四、详细实现步骤&#xff08;Part 2&#xff09;‌ ‌3. 参数化建模…...

Pytest项目_day01(HTTP接口)

HTTP HTTP是一个协议&#xff08;服务器传输超文本到浏览器的传送协议&#xff09;&#xff0c;是基于TCP/IP通信协议来传输数据&#xff08;HTML文件&#xff0c;图片文件&#xff0c;查询结果等&#xff09;。 访问域名 例如www.baidu.com就是百度的域名&#xff0c;我们想…...

在vue项目中,使用Patch请求,实现根据id修改某张发票的日结状态

目录 前言 一.问题描述 二.后端实现 1.分析 2.检查后端拦截器&#xff0c;看看是否允许接收Patch类型的请求 3.编写Dto 4.编写controller层 5.编写service层 6.mapper层 7.使用apifox&#xff0c;测试后端接口的可用性 三.前端实现 1.封装api&#xff08;本质是ax…...

Android Zygote的进程机制

目录 ✅ Android Zygote 进程机制详解 &#x1f6a9; 一、Zygote 的作用 ⚙️ 二、Zygote 启动流程 ✅ 1. init 进程启动 Zygote ✅ 2. Zygote 初始化虚拟机与核心类库 ✅ 3. Zygote 监听 Socket ✅ 4. Zygote fork 创建应用进程 &#x1f525; 三、Zygote 与应用进程之…...

某快餐店用户市场数据挖掘与可视化

1、必要库的载入 import pandas as pd import matplotlib.pyplot as plt import seaborn as sns2、加载并清洗数据 # 2.1 加载数据 df pd.read_csv(/home/mw/input/survey6263/mcdonalds.csv)# 2.2 数据清洗 # 2.2.1 检查缺失值 print(缺失值情况&#xff1a;) print(df.isn…...

[C++面试] 标准容器面试点

一、入门 1、vector和list的区别 [C面试] vector 面试点总结 vector 是动态数组&#xff0c;它将元素存储在连续的内存空间中。支持随机访问&#xff0c;即可以通过下标快速访问任意位置的元素&#xff0c;时间复杂度为 O(1)&#xff0c;准确点是均摊O(1)。但在中间或开头插…...

单片机学完开发板,如何继续提升自己的技能?

很多人学完开发板后都会卡在一个尴尬的阶段&#xff1a;觉得自己会的东西不少&#xff0c;但又不知道下一步该干啥。会点C语言&#xff0c;能烧录程序&#xff0c;能点亮LED&#xff0c;玩转按键&#xff0c;搞定串口等等&#xff0c;能用开发板做点小玩意儿&#xff0c;但面对…...

luogu「EZEC-10」打分 --- Python3 解法

题目链接&#xff1a; 「EZEC-10」打分 import sysdef max_score(n, m, scores):scores.remove(min(scores)) # 最小值的选取&#xff0c;不影响中间部分的处理scores.sort()max_ scores[-1]sum_ sum(scores[:-1]) # 中间部分len_ len(scores)needed (len_ - 1) * max_ …...

MySQL事务介绍

一、一个典型的事务场景 步骤操作描述SQL 语句1开启事务&#xff0c;确保转账操作的原子性START TRANSACTION;2从用户 A 的账户中扣除 100 元UPDATE account SET balance balance - 100 WHERE user A;3向用户 B 的账户中添加 100 元UPDATE account SET balance balance 1…...

明基PD2700U显示器无法调节图像模式

现象&#xff1a;明基PD2700U显示器无法调节图像模式&#xff0c;如下图&#xff1a; 目前未找到根本原因&#xff0c;推测可能是下面的原因&#xff1a; 1、安装了远程桌面软件&#xff1a;向日葵、虚拟显示器 2、显卡插入了接口&#xff0c;但是没接显示器 解决办法&#xf…...

基于FPGA轨道交通6U机箱CPCI脉冲板板卡

板卡简介&#xff1a; 本板为脉冲板&#xff0c;脉冲板主要执行CPU下达的指令&#xff0c;通过实现各种控制算法来调节PWM&#xff0c;然后输出光纤PWM信号来驱动变频器功率模块以达到控制电机的目的。 性能规格&#xff1a; 电源&#xff1a;DC5V&#xff1b;15V FPGA&…...

SpringBoot-已添加并下载的依赖,reload和mvn clean 后还是提示找不到jar包问题

背景&#xff1a; 添加spring-jdbc依赖时&#xff0c;原来是指定版本的&#xff0c;担心版本冲突&#xff0c;就改成依赖托管&#xff0c;悲剧的是反复reload和mvn clean&#xff0c;import到类的该包一直标红&#xff0c;提示jar包找不到。。。 解决方案&#xff1a; Idea左上…...

如何通过 Airbyte 将数据摄取到 Elasticsearch

作者&#xff1a;来自 Elastic Andre Luiz Airbyte 是一个数据集成工具&#xff0c;可自动化并可扩展地将信息从各种来源传输到不同的目的地。它使你能够从 API、数据库和其他系统提取数据&#xff0c;并将其加载到 Elasticsearch 等平台&#xff0c;以实现高级搜索和高效分析。…...

配置 VSCode 的 C# 开发环境

1. 安装必要的依赖 1.1 VSCode 扩展 安装 C# 相关插件&#xff08;如 C#、C# Extensions 等&#xff09;。 1.2 .NET SDK 下载地址&#xff1a;.NET SDK 下载页面 1.3 安装检测 在命令行输入以下命令&#xff0c;如果正确返回了版本号&#xff0c;则表示 .NET SDK 安装成…...

如何用DeepSeek进行项目管理?AI重构项目全生命周期的实践指南

一、项目管理的核心工作范畴 现代项目管理包含六大核心模块&#xff0c;构成完整管理闭环&#xff1a; 1. 需求管理&#xff08;20%工作量&#xff09; 案例&#xff1a;某电商平台"双11"大促项目需整合23个部门的142项需求 关键动作&#xff1a;需求收集→优先级…...

Git 回退操作详解:带示例的“小白”指南

前言 在日常开发中&#xff0c;我们难免会遇到&#xff1a; 改错代码&#xff1a;推送之前才发现某些行根本就不该动提交错误&#xff1a;commit 信息打错、提交到错误分支想回到之前版本&#xff1a;测试时发现之前版本是好的&#xff0c;需要回去查看 这就需要用到 Git 的…...

vue3 引入element-plus组件后,发现输入的时候没有提示,而且鼠标移到el-button显示unknown的简单解决方法

1、element-plus官方地址 一个 Vue 3 UI 框架 | Element Plus 2、安装 安装 | Element Plus 3、安装插件unplugin-vue-components、unplugin-auto-import并配制 快速开始 | Element Plus 4、输入关键词没有提示及ElButton:unknown的处理 1&#xff09;装个扩展插件&#xf…...