Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux epoll 高效 I/O 多路複用完整指南

編輯:Linux 教學

核心原理

epoll 是 Linux 內核提供的異步事件通知機制。應用程式不再輪詢,而是向內核註冊關注的文件描述符 (fd) 及事件類型;當 fd 就緒(可讀/可寫)時,內核通過 epoll_wait 主動通知應用層,應用層再發起實際 recv/send。epoll 不直接進行 I/O 讀寫,僅負責事件通知,保持通知與操作解耦,極大提升靈活性。

核心數據結構

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;     // 用戶自定義數據 (如 fd、指針)
};

events 取值

  • EPOLLIN:可讀 (含對端正常關閉)
  • EPOLLOUT:可寫
  • EPOLLPRI:帶外數據/緊急數據可讀
  • EPOLLERR:錯誤
  • EPOLLHUP:掛起/斷開
  • EPOLLET:邊緣觸發 (ET) 模式 (默認水平觸發 LT)
  • EPOLLONESHOT:一次性通知,處理完需重新註冊

三大核心 API

1. epoll_create

int epoll_create(int size);
// size: 提示內核監聽規模 (舊內核用於哈希表大小,新內核忽略)
// 返回: epoll 專用 fd (需 close 釋放)

2. epoll_ctl

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
// op: EPOLL_CTL_ADD (註冊) | EPOLL_CTL_MOD (修改) | EPOLL_CTL_DEL (刪除)
// event: 指定關注事件及用戶數據

3. epoll_wait

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
// events: 輸出數組,存放就緒事件
// maxevents: 數組容量 (≤ epoll_create 的 size)
// timeout: 毫秒;-1 永久阻塞,0 立即返回
// 返回: 就緒事件數;0 超時;-1 出錯

ET vs LT 模式深度解析

特性水平觸發 (LT, 默認)邊緣觸發 (ET)
通知條件fd 就緒狀態持續存在即反覆通知fd 狀態發生變化瞬間通知一次
編程模型可阻塞/非阻塞均可必須非阻塞 + 循環讀寫至 EAGAIN
遺漏風險無若未讀寫完畢,下次不再通知,導致數據滯留
適用場景簡單、穩健高併發、追求極致效能

epoll vs select/poll

  • 無 fd 上限: select 受 FD_SETSIZE (通常 1024) 限制;epoll 僅受系統最大 fd 數限制。
  • O(1) 事件就緒通知: select/poll 掃描全量 fd O(n);epoll 內核就緒鏈表直接回調 O(1)。
  • 用戶/內核數據零拷貝: epoll 通過 epoll_data 直接攜帶用戶數據指針,避免輪詢傳遞大量 fd 集合。

典型 ET 模式讀取框架

while (1) {
    int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
    for (int i = 0; i < n; ++i) {
        int fd = events[i].data.fd;
        if (events[i].events & EPOLLIN) {
            while (1) {
                ssize_t r = read(fd, buf, sizeof(buf));
                if (r > 0) process(buf, r);
                else if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) break; // 讀完
                else { close(fd); break; } // 錯誤或對端關閉
            }
        }
        // 處理 EPOLLOUT 同理
    }
}

總結

epoll 是 Linux 高併發網絡編程基石。掌握 LT/ET 差異、非阻塞配合、EPOLLONESHOT 線程安全用法,能構建百萬級併發服務器。

Copyright © Windows教程網 All Rights Reserved