epoll_event數據結構及使用案例詳解

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;它都能輕松勝…