多路复用epoll

Epoll:性能之王(红黑树+回调)

epoll 是为了解决大批量句柄处理而设计的

一、 Epoll 的核心工作原理

要理解 Epoll 的接口,首先要理解它在内核里建立的两个"秘密基地":

  1. 红黑树 (Red-Black Tree, rbr**)**:
    • 用来存储所有你想要监听的文件描述符(FD)。
    • select 每次都要把整个集合传给内核,而 Epoll 把这些 FD 存在内核的红黑树里,不需要重复拷贝 。增删查改的效率是 O(logN)
  1. 就绪双向链表 (Ready List, rdlist**)**:
    • 用来存储已经就绪(有数据来了)的事件。
    • 当网卡接收到数据,会触发回调函数 (ep_poll_callback),这个回调函数会自动把活跃的 FD 放入这个链表 5。
    • epoll_wait 不需要遍历所有连接,只需要检查这个链表是否为空即可,复杂度是 O(1)

二、 Epoll 的三个核心接口详解

Epoll 把 select 那个臃肿的一个函数拆分成了三个步骤,分别对应"建群"、"加人"、"等消息" 。

1. epoll_create ------ 创建管家(建群)
复制代码
int epoll_create(int size);
  • 功能 :创建一个 Epoll 的句柄(在内核中创建一个 eventpoll 对象)。
  • 参数 size
    • 这个参数其实是被忽略的,只要填一个大于 0 的数即可 。
  • 返回值 :成功返回一个 epoll 的文件描述符(epfd),失败返回 -1。
  • 注意 :Epoll 句柄本身也是一个文件描述符,占用一个 FD 资源,用完后必须调用 close() 关闭 。
2. epoll_ctl ------ 管理名单(加人/踢人)

这是 Epoll 与 Select 最大的不同点。Select 是在等待时才给名单,Epoll 是提前注册

复制代码
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  • 参数详解
    • epfdepoll_create 返回的那个句柄 。
    • op:要进行的操作动作,用宏表示 :
      • EPOLL_CTL_ADD:注册新的 FD 。
      • EPOLL_CTL_MOD:修改已有的 FD 监听事件 。
      • EPOLL_CTL_DEL:从红黑树中删除一个 FD 。
    • fd:需要监听的 socket 文件描述符 。
    • event:告诉内核你要监听什么事(读/写/异常)以及你留的"备注数据" 。

关键结构体 epoll_event

复制代码
struct epoll_event {
uint32_t     events;      // 监听的事件类型
epoll_data_t data;        // 用户数据(给用户自己用的)
};
    • events****取值
      • EPOLLIN:可读(包括对端关闭)。
      • EPOLLOUT:可写 。
      • EPOLLET开启边缘触发模式 (Edge Triggered)
    • data****联合体 : 这是一个联合体,你可以存 int fd,也可以存 void *ptr 指针。当事件就绪时,内核会把这个 data 原样还给你。
3. epoll_wait ------ 等待消息(收割)
复制代码
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
  • 功能 :收集在 Epoll 监控中已经发生的事件 。它直接查看内核的 rdlist 就绪链表,如果有数据,就拷贝给用户。
  • 参数详解
    • epfd:Epoll 句柄。
    • events输出参数。这是一个数组,内核会把就绪的事件复制到这里 。
    • maxevents:告诉内核这个数组有多大(不能大于创建时的 size,但现在 size 被忽略,主要是防止数组越界)。
    • timeout:超时时间(毫秒)。0 表示立即返回(非阻塞),-1 表示永久阻塞,>0 表示等待指定时间 。
  • 返回值
    • > 0:就绪的文件描述符个数。
    • 0:超时。
    • -1:出错 。

三、 Epoll 的两种工作模式:LT vs ET

1. LT 模式 (Level Triggered) ------ 水平触发
  • 默认模式
  • 机制 :只要 socket 接收缓冲区里还有数据,epoll_wait 就会一直通知你 。
  • 例子 :缓冲区有 2KB 数据,你只读了 1KB。下次调用 epoll_wait,它会再次返回并告诉你"有数据读" 。
  • 特点:支持阻塞和非阻塞读写,编程不容易出错 。Select 和 Poll 本质上也是 LT 模式 。
2. ET 模式 (Edge Triggered) ------ 边缘触发
  • 高性能模式(Nginx 默认采用)。
  • 机制:只有当状态发生变化时(从无数据变成有数据),内核才会通知一次 。
  • 例子 :缓冲区有 2KB 数据,你只读了 1KB。下次调用 epoll_wait它不会再通知你了 ,剩下的 1KB 数据会一直待在缓冲区里,直到下一次有数据到来 。
  • 要求
    1. 必须配合 非阻塞 I/O (Non-blocking IO) 使用 。
    2. 必须使用循环 (while) 读取,直到 read 返回 EAGAIN 错误,确保把缓冲区读空 。
  • 优点 :减少了 epoll_wait 返回的次数,系统调用开销更小 。
相关推荐
陌路2011 小时前
操作系统(15)--进程与线程
linux·运维·服务器
航Hang*11 小时前
第八章:网络系统建设与运维(高级)—— 服务质量
运维·服务器·网络·笔记·ensp
航Hang*11 小时前
第九章:网络系统建设与运维(高级)—— 无线局域网
网络·笔记·学习·华为·ensp·交换机
会打莎士比亚的猴子11 小时前
tcpdump移植
网络·测试工具·tcpdump
Howrun77711 小时前
Linux---内核态&用户态
linux
QT 小鲜肉11 小时前
【Linux命令大全】002.文件传输之ftpwho命令(实操篇)
linux·运维·服务器·网络·chrome·笔记
智者知已应修善业11 小时前
【组合数】2024-3-16
c语言·c++·经验分享·笔记·算法
应用市场11 小时前
Linux进程调度与多核CPU深度解析——从内核调度器到实战优化
linux·运维·服务器
帝落若烟11 小时前
ubuntu安装禅道
linux·运维·ubuntu