epoll_event 事件類型詳解

epoll_event 事件類型詳解

epoll_event 是 Linux epoll I/O 多路復用機制的核心結構體,其中的事件類型決定了 epoll 監控的行為和觸發條件。以下是各種事件類型的詳細解析:

epoll_event 結構體

#include <sys/epoll.h>typedef union epoll_data {void    *ptr;int      fd;uint32_t u32;uint64_t u64;
} epoll_data_t;struct epoll_event {uint32_t     events;   // 事件類型標志位(位掩碼)epoll_data_t data;     // 用戶數據(通常存儲文件描述符)
};

事件類型標志位 (events)

事件類型值 (十六進制)說明觸發條件
EPOLLIN0x001可讀事件接收緩沖區有數據可讀 (≥1字節)
EPOLLOUT0x004可寫事件發送緩沖區有空間可寫
EPOLLRDHUP0x2000對端關閉連接 (需內核≥2.6.17)TCP連接對端關閉寫端 (半關閉) 或完全關閉
EPOLLPRI0x002緊急數據事件收到帶外數據 (OOB) 或 TCP 緊急數據
EPOLLERR0x008錯誤事件文件描述符發生錯誤 (自動監控,無需顯式設置)
EPOLLHUP0x010掛起事件文件描述符被掛起 (如管道寫端關閉后讀端)
EPOLLET0x80000000邊緣觸發模式 (默認水平觸發)設置后進入邊緣觸發模式
EPOLLONESHOT0x40000000單次觸發模式事件觸發后自動禁用監控,需重新EPOLL_CTL_MOD啟用
EPOLLWAKEUP0x20000000防止系統休眠 (需內核≥3.5)事件處理期間阻止系統進入休眠狀態
EPOLLEXCLUSIVE0x10000000獨占喚醒 (需內核≥4.5)避免驚群效應,多個等待進程中只喚醒一個

核心事件詳解

1. EPOLLIN (可讀事件)

  • 觸發條件
    • 套接字接收緩沖區有數據可讀
    • 監聽套接字有新連接到達
    • TCP對端關閉連接 (觸發EPOLLIN+讀取返回0)
    • 管道/FIFO的寫端關閉
  • 使用場景
    // 監控套接字可讀
    event.events = EPOLLIN;
    epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);
    

2. EPOLLOUT (可寫事件)

  • 觸發條件
    • 套接字發送緩沖區有空間可寫入
    • 非阻塞connect()連接完成
  • 注意事項
    • 水平觸發模式下會持續觸發直到緩沖區滿
    • 通常只在需要時啟用,避免CPU空轉
  • 使用技巧
    // 只在需要寫入時啟用EPOLLOUT
    event.events = EPOLLIN;  // 默認只監控讀
    if (need_write) {event.events |= EPOLLOUT; // 動態添加寫監控
    }
    epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &event);
    

3. EPOLLRDHUP (對端關閉)

  • 優勢
    • 替代EPOLLIN + read() == 0的檢測方式
    • 更高效檢測TCP半關閉狀態
  • 使用示例
    // 檢測連接關閉
    event.events = EPOLLIN | EPOLLRDHUP;
    
  • 觸發條件
    • 收到FIN包 (TCP對端調用shutdown(SHUT_WR)close())

4. EPOLLET (邊緣觸發)

  • 工作模式對比
    特性水平觸發 (LT)邊緣觸發 (ET)
    觸發條件狀態滿足即觸發狀態變化時觸發
    事件通知頻率高 (持續通知)低 (僅變化時通知)
    數據處理要求可分批處理必須一次處理完所有數據
    緩沖區處理無需完全清空必須完全清空緩沖區
    性能較低更高
  • ET模式注意事項
    1. 必須使用非阻塞I/O
    2. 必須一次性讀取/寫入所有數據
    3. 需要手動跟蹤未完成操作
    // 邊緣觸發設置
    event.events = EPOLLIN | EPOLLET;
    

高級事件類型

5. EPOLLONESHOT (單次觸發)

  • 設計目的
    • 防止多線程同時操作同一文件描述符
    • 確保事件只被一個線程處理
  • 工作流程
    注冊EPOLLONESHOT
    事件觸發
    工作線程處理
    需要繼續監控?
    重新注冊EPOLL_CTL_MOD
    關閉連接
  • 代碼示例
    // 設置單次觸發
    event.events = EPOLLIN | EPOLLONESHOT;
    epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);// 處理完成后重新啟用
    event.events = EPOLLIN | EPOLLONESHOT; // 保持設置
    epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event);
    

6. EPOLLEXCLUSIVE (獨占喚醒)

  • 解決驚群問題
    • 多個進程監聽同一端口時,只喚醒一個進程
    • 替代SO_REUSEPORT的解決方案
  • 使用限制
    • 僅對EPOLL_CTL_ADD操作有效
    • 必須與EPOLLIN或EPOLLOUT同時使用
    // 多進程避免驚群
    event.events = EPOLLIN | EPOLLEXCLUSIVE;
    

事件組合與典型場景

常見事件組合

應用場景推薦事件組合說明
TCP服務器監聽套接字EPOLLIN接受新連接
TCP數據接收`EPOLLINEPOLLRDHUP [
TCP數據發送EPOLLOUT (動態啟用)緩沖區可寫時發送
非阻塞connectEPOLLOUT連接完成時可寫
錯誤檢測(自動包含)無需設置,總是監控
高并發服務器`EPOLLINEPOLLET
多線程安全處理`EPOLLINEPOLLONESHOT`

完整事件處理示例

#define MAX_EVENTS 10
struct epoll_event events[MAX_EVENTS];while (1) {int n = epoll_wait(epfd, events, MAX_EVENTS, -1);for (int i = 0; i < n; i++) {int fd = events[i].data.fd;uint32_t revents = events[i].events;// 1. 錯誤處理(優先檢查)if (revents & EPOLLERR) {int error = 0;socklen_t errlen = sizeof(error);getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &errlen);close(fd);continue;}// 2. 連接關閉if (revents & EPOLLRDHUP) {close(fd); continue;}// 3. 可讀事件if (revents & EPOLLIN) {if (fd == listen_fd) {// 接受新連接accept_new_connection(fd);} else {// 處理客戶端數據handle_client_data(fd);}}// 4. 可寫事件if (revents & EPOLLOUT) {send_pending_data(fd);// 數據發完后關閉寫監控struct epoll_event ev;ev.events = EPOLLIN | EPOLLET; // 移除EPOLLOUTepoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev);}}
}

最佳實踐與陷阱規避

  1. 必須處理的錯誤事件

    // EPOLLERR 必須處理,否則可能導致死循環
    if (events[i].events & EPOLLERR) {// 獲取具體錯誤碼int err;socklen_t len = sizeof(err);getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);printf("Error on fd %d: %s\n", fd, strerror(err));close(fd);
    }
    
  2. ET模式下的讀寫要求

    // ET模式必須循環讀取直到EAGAIN
    while (1) {ssize_t count = read(fd, buf, sizeof(buf));if (count == -1) {if (errno == EAGAIN) break; // 數據讀完// 處理其他錯誤break;}if (count == 0) { // 連接關閉close(fd);break;}// 處理數據...
    }
    
  3. 避免EPOLLOUT誤用

    • 不要長期啟用EPOLLOUT,只在有數據要發送時啟用
    • 發送完成后立即移除EPOLLOUT監控
    // 啟用寫監控
    event.events = current_events | EPOLLOUT;
    epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event);// 發送完成后禁用
    event.events = current_events & ~EPOLLOUT;
    epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event);
    
  4. 性能優化建議

    • 高并發場景優先使用ET模式
    • 短連接服務使用LT更簡單
    • 多核處理器結合SO_REUSEPORT+EPOLLEXCLUSIVE

💡 經驗法則:理解每種事件類型的觸發機制和適用場景是構建高性能網絡程序的基礎。EPOLLRDHUP和EPOLLET的組合是現代Linux高性能服務器的黃金標準。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/93167.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/93167.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/93167.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

設計自己的小傳輸協議 導論與概念

設計自己的小傳輸協議 導論與概念 1&#xff1a;聊一聊協議頭設計 ? 早在《TCP/IP詳解》中的第一句話中&#xff0c;我們就知道協議的含義是這樣的&#xff1a;協議是通信雙方共同遵守的一套規則&#xff0c;提供格式定義、語義解釋等&#xff0c;使不同設備或軟件能夠正確交…

iOS —— 天氣預報仿寫總結

在iOS中&#xff0c;最常見的網絡請求方式是NSURLSession&#xff0c;它是蘋果推薦的現代API&#xff0c;簡單安全且易于拓展。一次完整的網絡請求流程&#xff1a;構造 NSURL 對象創建 NSURLSessionDataTask發起請求&#xff08;resume&#xff09;在回調中解析數據回到主線程…

MySQL 8.4 Windows 版安裝記錄與步驟參考

導語&#xff1a; MySQL 作為廣泛使用的開源數據庫管理系統&#xff0c;是許多開發者和學習者的必備工具。最近有朋友詢問安裝過程&#xff0c;正好整理了 MySQL 8.4 在 Windows 系統下的安裝步驟和一些注意事項&#xff0c;分享給有需要的朋友做個參考。關于 MySQL&#xff1a…

七、搭建springCloudAlibaba2021.1版本分布式微服務-skywalking9.0鏈路追蹤

前言鏈路追蹤介紹 對于一個大型的幾十個&#xff0c;幾百個微服務構成的微服務架構系統&#xff0c;通常會遇到下面的一系列問題。 如何串聯整個調用鏈路&#xff0c;快速定位問題&#xff1f;如何澄清各個微服務之間的依賴關系&#xff1f;如何進行各個微服務接口的性能分析&a…

深入理解大語言模型生成參數:temperature、top\_k、top\_p 等全解析

在使用大語言模型&#xff08;如 GPT-4、LLaMA、ChatGLM 等&#xff09;進行文本生成任務時&#xff0c;很多開發者會面對各種“生成參數”&#xff0c;如 temperature、top_k、top_p、repetition_penalty 等。這些參數雖然看起來抽象&#xff0c;但掌握它們的意義和配置技巧&a…

vulhub Web Machine(N7)靶場攻略

下載地址&#xff1a; https://download.vulnhub.com/webmachine/Web-Machine-N7.ova 使用方法&#xff1a; 靶場下載好以后不用解壓&#xff0c;需要使用Oracle VirtualBox虛擬機打開&#xff0c;用VMware會報錯。安裝Oracle VirtualBox虛擬機時安裝地址不能隨便選擇&#…

【機器學習深度學習】模型微調:多久才算微調完成?——如何判斷微調收斂,何時終止訓練

目錄 前言 一、微調過程的目標&#xff1a;優化模型表現 二、微調需要多久&#xff1f; 微調時間無法確定 三、如何判斷微調何時收斂&#xff1f; 3.1 觀察Loss的下降趨勢 3.2 損失值趨于平穩&#xff0c;意味著收斂 如何識別收斂&#xff1f; 3.3 驗證Loss的波動&…

紅隊視角:實戰滲透測試中漏洞利用的進階技巧與防御

紅隊作為滲透測試的 “攻擊方”&#xff0c;其核心價值不僅在于發現漏洞&#xff0c;更在于挖掘漏洞的深度利用方式 —— 通過繞過防護措施、組合低危漏洞形成攻擊鏈&#xff0c;暴露企業真實安全風險。從紅隊視角解析漏洞利用的進階技巧&#xff0c;既能幫助防御方理解攻擊思路…

OpenHarmony BUILD.gn中執行腳本

在OpenHarmony編譯構建中筆者經常遇到這樣的場景——需要執行sh腳本完成某些操作。筆者將OpenHarmony BUILD.gn中執行腳本的方法分享如下&#xff1a; 前置知識點 1.能夠把自定義的子系統加入OpenHarmony源碼的編譯構建&#xff0c;請參考&#xff1a;https://ost.51cto.com/…

QUIC協議如何在UDP基礎上解決網絡切換問題

一、UDP 四元組的本質局限UDP 本身無連接狀態&#xff0c;其數據包僅通過四元組尋址。但 QUIC 在 UDP 之上構建了完整的連接語義。二、QUIC 的連接遷移核心機制1. 連接標識符&#xff08;Connection ID&#xff09;關鍵設計&#xff1a;每個 QUIC 連接擁有全局唯一 64-bit Conn…

力扣131:分割回文串

力扣131:分割回文串題目思路代碼題目 給你一個字符串 s&#xff0c;請你將 s 分割成一些 子串&#xff0c;使每個子串都是 回文串 。返回 s 所有可能的分割方案。 思路 從題目中我們可以總結出這道題的三個需要解決的問題&#xff1a; 如何判斷回文串如何找到一種方案里的所…

代駕小程序系統開發:引領出行行業數字化轉型

隨著數字技術的飛速發展&#xff0c;出行行業正經歷著深刻的數字化轉型。代駕小程序系統作為這一轉型的重要推手&#xff0c;以其高效、便捷、智能的特點&#xff0c;引領著出行行業向數字化、網絡化、智能化方向發展。一、數字化管理&#xff0c;提升運營效率代駕小程序系統通…

數獨求解器與生成器(回溯算法實現)

摘要本畢業設計旨在利用MATLAB技術實現一個基于回溯算法的數獨求解器與生成器。通過深入分析數獨游戲的規則和回溯算法的原理&#xff0c;設計并實現了數獨求解的核心算法&#xff0c;同時開發了數獨生成功能&#xff0c;能夠生成符合規則的有效數獨謎題。系統采用MATLAB圖形用…

[數據結構]#7 哈希表

哈希表&#xff08;Hash Table&#xff09;&#xff0c;有時也稱為散列表&#xff0c;是一種數據結構&#xff0c;它提供了一種快速存取數據的方法。哈希表利用一個被稱為哈希函數的機制將鍵映射到表中的一個位置來直接訪問記錄&#xff0c;以此加快查找的速度。哈希表通常支持…

C++ 23種設計模式-工廠模式

工廠模式是一種創建型的設計模式&#xff0c;他提供了一種創建對象的最佳方式&#xff0c;而無需指定將要創建對象的具體類。包括&#xff1a;簡單工廠模式、工廠方法模式、抽象工廠模式。簡單工廠模式組成成員&#xff1a;抽象產品類、具體產品類 A、B、C等、工廠類工作原理&a…

vue3 el-table 行的某個特定值來決定某些列是否顯示

在 Vue 3 中使用 Element Plus 的 <el-table> 組件時&#xff0c;如果你想要根據行的某個特定值來決定某些列是否顯示&#xff0c;你可以通過自定義列渲染函數&#xff08;render 函數&#xff09;來實現這一需求。下面是一個如何實現該功能的步驟說明和示例代碼。步驟 1…

電商數據采集API與爬蟲技術結合的全網比價方案

一、技術選型與工具準備API優先策略官方API接入&#xff1a;京東、淘寶、拼多多等平臺提供商品詳情API&#xff0c;需注冊開發者賬號獲取API Key。例如&#xff1a;京東API支持實時獲取商品價格、庫存、評價數據。淘寶API通過RESTful接口返回JSON格式的商品信息&#xff0c;需O…

Socket詳解

一.定義Socket&#xff08;套接字&#xff09;是網絡編程的核心&#xff0c;它允許不同主機或同一主機的不同進程之間進行通信&#xff0c;Socket API 提供了一套標準的接口&#xff0c;支持 TCP、UDP、IP 等協議分為以下三個類型&#xff1a;SOCK_STREAM: 用于tcp協議&#xf…

如何實現打印功能

一、AI賦能提供思路基本框架<!-- 隱藏的打印內容&#xff08;默認不顯示&#xff09; --> <div id"print-container" style"display: none;"><h1>退貨單打印內容</h1><table><!-- 打印專用的表格結構 --></table&g…

Android 架構演進:從 MVC 到 MVVM 的設計之道

在 Android 開發初期&#xff0c;很多開發者會把所有邏輯塞進 Activity—— 網絡請求、數據處理、UI 更新全堆在一起&#xff0c;導致代碼超過數千行&#xff0c;改一個按鈕點擊都要翻半天。這種 “面條式代碼” 的根源是缺乏架構設計。隨著應用復雜度提升&#xff0c;MVC、MVP…