epoll_event 数据结构详解

在 Linux 的 I/O 多路复用机制 epoll 中,epoll_event 是关键的数据结构,用于描述文件描述符(fd)上的事件和关联数据。其定义在头文件 <sys/epoll.h> 中:

struct epoll_event {uint32_t     events;    // 事件掩码(位图)epoll_data_t data;      // 用户数据(联合体)
};typedef union epoll_data {void    *ptr;    // 自定义指针(常用)int      fd;     // 关联的文件描述符(常用)uint32_t u32;    // 32位整数uint64_t u64;    // 64位整数
} epoll_data_t;
核心字段解析:
  1. events (事件标志位)

    • EPOLLIN:fd 可读(有数据到达)
    • EPOLLOUT:fd 可写(可发送数据)
    • EPOLLERR:fd 发生错误
    • EPOLLHUP:fd 被挂断(对端关闭连接)
    • EPOLLET:启用边缘触发模式(默认水平触发)
    • EPOLLRDHUP:流套接字对端关闭连接(或半关闭)
  2. data (用户数据联合体)

    • 常用 fdptr 存储与事件相关的自定义数据(如连接上下文)

使用案例:基于 ET 模式的 Echo 服务器

以下示例展示 epoll_event 在非阻塞 TCP 服务器中的典型用法(边缘触发模式):

#include <sys/epoll.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>#define MAX_EVENTS 64
#define PORT 8080// 设置 fd 为非阻塞模式
void set_nonblocking(int fd) {int flags = fcntl(fd, F_GETFL, 0);fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}int main() {int server_fd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in addr = {.sin_family = AF_INET,.sin_port = htons(PORT),.sin_addr.s_addr = INADDR_ANY};// 绑定并监听bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));listen(server_fd, SOMAXCONN);// 创建 epoll 实例int epoll_fd = epoll_create1(0);struct epoll_event ev, events[MAX_EVENTS];// 添加 server_fd 到 epollev.events = EPOLLIN | EPOLLET;  // 边缘触发模式ev.data.fd = server_fd;         // 存储文件描述符epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev);while (1) {int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);for (int i = 0; i < nfds; i++) {// 处理新连接if (events[i].data.fd == server_fd) {struct sockaddr_in client_addr;socklen_t len = sizeof(client_addr);int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len);set_nonblocking(client_fd);// 注册客户端 fdev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;ev.data.fd = client_fd;  // 存储客户端 fdepoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev);}// 处理客户端数据else if (events[i].events & EPOLLIN) {int client_fd = events[i].data.fd;  // 取出 fdchar buffer[1024];ssize_t bytes_read;// ET 模式需循环读取所有数据while ((bytes_read = read(client_fd, buffer, sizeof(buffer))) {if (bytes_read > 0) {write(client_fd, buffer, bytes_read);  // Echo 回显} else if (bytes_read == 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) {close(client_fd);  // 关闭连接break;}}}// 处理连接关闭else if (events[i].events & (EPOLLRDHUP | EPOLLHUP)) {close(events[i].data.fd);  // 关闭失效连接}}}close(server_fd);return 0;
}
关键逻辑说明:
  1. 事件注册

    • 通过 epoll_ctl() 添加 fd 时,初始化 epoll_event 结构:
      ev.events = EPOLLIN | EPOLLET;  // 订阅事件类型
      ev.data.fd = server_fd;          // 存储关联的 fd
      
  2. 事件处理

    • epoll_wait() 返回就绪的 epoll_event 数组
    • 通过 events[i].data.fd 取出关联的 fd
    • 通过 events[i].events 判断具体事件类型
  3. 边缘触发 (ET) 要点

    • 必须循环读写直到返回 EAGAIN
    • 需配合非阻塞 fd 避免阻塞

常见使用技巧

  1. 自定义数据存储

    • 使用 data.ptr 存储复杂结构体(如连接上下文):
      struct connection {int fd;struct sockaddr_in addr;
      };struct connection *conn = malloc(sizeof(*conn));
      conn->fd = client_fd;
      ev.data.ptr = conn;  // 存储指针
      
  2. 事件组合

    • 错误处理:EPOLLERR | EPOLLHUP
    • 读写监听:EPOLLIN | EPOLLOUT
  3. 触发模式选择

    • 水平触发 (LT):未处理事件会持续通知(默认)
    • 边缘触发 (ET):事件就绪时只通知一次(性能更高)

性能提示:ET 模式 + 非阻塞 I/O 是 epoll 高性能的关键组合,适合高并发场景。

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

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

相关文章

C++11STL容器map和set简单介绍

一、引言map和set底层结构比较复杂&#xff0c;我认为我们先谈基本介绍再谈C11&#xff0c;最后再谈map和set底层以及map和set封装。二、简单介绍一下map和setmap和set底层都是红黑树&#xff0c;是二叉搜索树的一种&#xff0c;查找非常快。不像数组、链表一样一个一个对比&am…

Java线程基础面试复习笔记

1. 线程与进程的区别进程是正在运行程序的实例&#xff0c;线程是进程中的执行单元。主要区别&#xff1a; 内存空间&#xff1a;不同进程使用不同的内存空间&#xff0c;同一进程下的线程共享内存空间资源开销&#xff1a;线程更轻量&#xff0c;线程上下文切换成本比进程上下…

面试题(技术面+hr面)

面试技术面HR面后端HR面常见问题*稳定性&#xff0c;上进心&#xff0c;目标感&#xff0c;抗压能力&#xff0c;学习能力*回答问题时注意体现上面五点&#xff0c;即使瞎扯也尽量往上靠。面经项目相关介绍一下你收获最大的一个项目你们团队有多少人&#xff0c;怎么分工的开发…

本地部署Dify教程

克隆 Dify 代码仓库克隆 Dify 源代码至本地。git clone hts://github.com/langgenius/dify.git启动 Dify进入 Dify 源代码的 docker 目录&#xff0c;执行一键启动命令:cd dify/docker #切换到指定目录 cp .env.example .env #修改文件名 docker compose up -d #启动

Android Kotlin 协程全面指南

协程是 Kotlin 提供的一套简化异步编程的轻量级线程操作框架&#xff0c;特别适合 Android 开发中的异步任务处理。以下是 Android 开发中需要掌握的协程核心知识点&#xff1a;1. 协程基础概念1.1 协程是什么轻量级线程&#xff1a;比线程更高效&#xff0c;可以在单个线程中运…

【Linux】进程切换与优先级

前言&#xff1a; 上文我们讲到了操作系统与Linux中进程的状态【Linux】进程状态-CSDN博客 本文我们来讲进程的优先级、以及进程的切换 进程优先级 什么是优先级&#xff1f; CPU中资源是有限的&#xff0c;而进程的数量一定是远大于CPU资源的&#xff0c;所以优先级是进程得…

首发即开源!DAWorkBench数据可视化分析软件正式发布!(附源码下载网址)

1 系统介绍DAWorkBench是一款面向科研实验和工程测试场景的数据可视化分析开源软件&#xff0c;支持实现数据清洗、信号处理和交互式可视化等功能。系统集成文件IO、数据处理以及可视化交互三大模块&#xff0c;支持多维数据分析与高质量图表生成&#xff0c;助力用户高效完成从…

Android Studio历史版本快速下载(二次修改记录)

原版&#xff1a;Android Studio历史版本快速下载_android studio 历史版本下载-CSDN博客 一. 最新版本 https://developer.android.com/studio?hlzh-cn 二. 历史版本 中国官网的历史版本为何不能下载&#xff1f;&#xff08;https://developer.android.com/studio/archi…

The Missing Semester of Your CS Education 学习笔记以及一些拓展知识(六)

文章目录The Missing Semester of Your CS Education 学习笔记以及一些拓展知识版本控制Git笔记部分Git的基本工作原理Git 的核心工作原理&#xff1a;快照而非差异Git 的三大工作区域Git的核心对象Git的四个对象对象之间的关系与工作流程&#xff1a;对象的引用Git的安装和基础…

嵌入式与 Linux 系统中的核心图形库全解析

嵌入式与 Linux 系统中的核心图形库全解析 图形库在嵌入式系统与 Linux 桌面系统中扮演着重要角色。从最底层的 GPU 驱动接口&#xff0c;到上层的图形渲染与 GUI 工具包&#xff0c;共同构成了完整的图形显示栈。本文将系统整理图形相关的核心组件&#xff0c;按功能分层分类&…

深度学习模块实践手册(第十二期)

56、Ghost 模块论文《GhostNet: More Features from Cheap Operations》1、作用&#xff1a; Ghost 模块是一种轻量级的特征提取模块&#xff0c;旨在通过廉价操作生成更多特征图&#xff0c;减少计算量的同时保持模型性能。传统卷积神经网络在生成特征图时存在大量冗余计算&am…

自己动手造轮子:如何创建JAR并通过Maven在Spring Boot中引用

让代码复用变得简单优雅——3分钟学会封装专属工具库作为Java开发者&#xff0c;你是否遇到过这些痛点&#xff1f;多个项目重复编写相同工具类工具代码分散难以统一维护团队协作缺乏标准化工具库本文将手把手教你创建自己的JAR包&#xff0c;并优雅地集成到Spring Boot项目中&…

使用dea工具 给vue 里面的ts打断点

在 Vue 项目中使用 TypeScript 时&#xff0c;我们通常会在 IDE&#xff08;如 JetBrains 的 IntelliJ IDEA 或 WebStorm&#xff09;中设置断点进行调试。以下是详细步骤&#xff1a; 准备工作 确保项目已配置 source maps&#xff08;Vue CLI 创建的项目默认已配置&#xff0…

Zabbix 企业级分布式监控

目录 简介 一、监控系统基础 1.1 监控的价值 1.2 监控的 5 大类型与 5 大层次 1.3 监控系统的实现原理 二、Zabbix&#xff1a;企业级监控方案 2.1 Zabbix 简介 2.2 Zabbix 核心功能特性 2.3 Zabbix 角色与架构 三、Zabbix 部署案例 3.1 资源清单 3.2 基础环境配置…

SQL JOIN 全解析:用 `users` 与 `orders` 表彻底掌握内连接、左连接、右连接

SQL JOIN 全解析&#xff1a;用 users 与 orders 表彻底掌握内连接、左连接、右连接 在日常开发中&#xff0c;SQL 的连接&#xff08;JOIN&#xff09;语句是数据库查询的核心技能。尤其在多表联合查询时&#xff0c;不掌握好 INNER JOIN、LEFT JOIN、RIGHT JOIN&#xff0c;…

(一)从零搭建unity3d机械臂仿真-unity3d导入urdf模型

1.新建工程并加载模型 &#xff08;1&#xff09;unity中新建3d工程 &#xff08;2&#xff09;将机器人模型导入到unity3d中 导入开源Unity-Robotics-Hub的机械臂。 详细操作参考视频 ROS Unity URDF Import Testing Robot Motion 使用 URDF Importer工具 在 Unity 中&#x…

Linux之网络部分-应用层自定义协议与序列化

一、应用层 1.1、理解协议 协议是一种 "约定". socket api 的接口, 在读写数据时, 都是按 "字符串" 的方式来发送接收的。如果我们要传输一些 "结构化的数据" 怎么办呢? 其实&#xff0c;协议就是双方约定好的结构化的数据。 1.2、网络版计…

机器学习week3-分类、正则化

1. 逻辑回归1.1. 线性回归 vs 逻辑回归对比维度线性回归逻辑回归任务类型回归&#xff08;预测连续值&#xff09;分类&#xff08;预测离散类别&#xff09;输出范围(−∞,∞)[0,1]&#xff08;概率值&#xff09;损失函数均方误差&#xff08;MSE&#xff09;对数损失&#x…

FastAdmin 中生成插件

在 FastAdmin 中生成一个 OCR 发票识别插件&#xff0c;可以按照以下步骤进行开发。这里假设你已经熟悉 FastAdmin 插件开发的基本流程&#xff0c;并会使用 Composer 和 PHP 扩展。1. 创建插件骨架使用 FastAdmin 命令行工具生成插件基础结构&#xff1a;php think addon -a o…

DevExpress WinForms中文教程:Grouping(分组)- 如何自定义分组算法?

DevExpress WinForms拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜…