高并发服务的核心机制——IO多路转接--->epoll

目录

引言

三个系统调用

epoll模型

epoll工作方式


引言

epoll是在Linux内核里重新添加的一套机制,它是在2.5.44内核中被引进的epoll(4),它可以批量的监控文件描述符的各种事件。

三个系统调用

在头文件#include <sys/epoll.h>中

cpp 复制代码
 int epoll_create(int size);

用于创建epoll模型,返回值是一个文件描述符,也可以理解为epoll模型的一个句柄(Linux里一切接文件)。这个epoll模型是什么后文详细介绍。在Linux2.6.8之后epoll_create的参数是被忽略的,我们只需传入一个非负整数即可。

cpp 复制代码
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

第一个参数:传入epoll模型对应的文件描述符
第二个参数:传入对epoll模型的操作

|--------------------------------|
| EPOLL_CTL_ADD :注册新的fd到epfd中; |
| EPOLL_CTL_MOD :修改已经注册的fd的监听事件; |
| EPOLL_CTL_DEL :从epfd中删除一个fd; |

第三个参数:要监控的文件描述符

第四个参数:要监控的事件
struct epoll_event 结构如下

cpp 复制代码
typedef union epoll_data
{
    void *ptr;          // 指向用户自定义数据的指针
    int fd;            // 文件描述符
    uint32_t u32;      // 32 位整数
    uint64_t u64;      // 64 位整数
} epoll_data_t;

struct epoll_event
{
    uint32_t events;    // 发生的事件
    epoll_data_t data;  // 用户数据
} __EPOLL_PACKED;      // 确保本结构体不被填充
  • events (uint32_t):

    • 这个字段指定了关注的事件类型,比如 EPOLLIN(可读事件)、EPOLLOUT(可写事件)等。可以使用按位或运算组合多个事件。
  • data (epoll_data_t):

    • 这个字段是一个联合体,允许存储不同类型的数据。通常用来保存与事件关联的文件描述符或者指向用户结构的指针。你可以使用以下方式之一来存储数据:
      • ptr: 通用指针,指向用户自定义的数据结构。
      • fd: 文件描述符。
      • u32u64: 32 位和 64 位整数,可以用于存储任意附加信息。

events可以是以下几个宏的集合:
EPOLLIN : 表示对应的文件描述符可以读 (包括对端SOCKET正常关闭);
EPOLLOUT : 表示对应的文件描述符可以写;
EPOLLPRI : 表示对应的文件描述符有紧急的数据可读 (这里应该表示有带外数据到来);
EPOLLERR : 表示对应的文件描述符发生错误;
EPOLLHUP : 表示对应的文件描述符被挂断;
EPOLLET : 将EPOLL设为边缘触发(Edge Triggered)模式, 这是相对于水平触发(Level Triggered)来说的.
EPOLLONESHOT :只监听一次事件, 当监听完这次事件之后, 如果还需要继续监听这个socket的话, 需要再次把这个socket加入到EPOLL队列里

cpp 复制代码
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

参数events是分配好的epoll_event结构体数组.
epoll将会把发生的事件赋值到events数组中 (events不可以是空指针,内核只负责把数据复制到这个events数组中,不会去帮助我们在用户态中分配内存).
maxevents告之内核这个events有多大,这个 maxevents的值不能大于创建epoll_create()时的size.
参数timeout是超时时间 (毫秒,0会立即返回,-1是永久阻塞).
如果函数调用成功,返回对应I/O上已准备好的文件描述符数目,如返回0表示已超时, 返回小于0表示函数失败.

epoll模型

当某一进程调用epoll_create方法时,Linux内核会创建一个eventpoll结构体。要监控的事件被连入到内核的红黑树结构中。

当就有文件描述符上的事件就绪了,epoll模型中还有一个双向链表结构,这个数据结构用来存放就绪事件,epoll_wait就是在这上面捞取就绪事件。

epoll工作方式

epoll有2种工作方式-水平触发(LT)和边缘触发(ET)。
水平触发Level Triggered 工作模式
epoll默认状态下就是 LT 工作模式 .
当epoll 检测到 socket 上事件就绪的时候 , 可以不立刻进行处理 . 或者只处理一部分 .
如上面的例子 , 由于只读了 1K 数据 , 缓冲区中还剩 1K 数据 , 在第二次调用 epoll_wait 时 , epoll_wait
仍然会立刻返回并通知 socket 读事件就绪 . 直到缓冲区上所有的数据都被处理完, epoll_wait 才不会立刻返回 .
边缘触发Edge Triggered 工作模式
如果我们在第1 步将 socket 添加到 epoll 描述符的时候使用了 EPOLLET 标志 , epoll 进入 ET 工作模式 .
当epoll 检测到 socket 上事件就绪时 , 必须立刻处理 .
如上面的例子, 虽然只读了 1K 的数据 , 缓冲区还剩 1K 的数据 , 在第二次调用 epoll_wait 的时候 ,
epoll_wait 不会再返回了 . 也就是说, ET 模式下 , 文件描述符上的事件就绪后 , 只有一次处理机会 .
ET的性能比 LT 性能更高 ( epoll_wait 返回的次数少了很多 ). Nginx 默认采用 ET 模式使用 epoll.
只支持非阻塞的读写

相关推荐
呆呆的猫7 分钟前
【多模态】46、DeepSeek-OCR | 一张图片是否真能抵千词
ocr·1024程序员节
Hefin_H20 分钟前
Linux 多用户服务器限制单用户最大内存使用(systemd user.slice)
linux·运维·服务器
唯鹿30 分钟前
Copilot使用体验
ai·1024程序员节
蔚蓝星辰mic31 分钟前
数据库运维查询SQL语句集合
数据库·sql·1024程序员节
金仓拾光集32 分钟前
终结工艺数据分散管理:金仓数据库平替MongoDB,实现参数、配方、流程一体贯通
1024程序员节
nassi_43 分钟前
开发板网络配置
linux·网络·嵌入式硬件
Better Bench44 分钟前
Ubuntu 20.04上安装MuJoCo 210
1024程序员节
傻啦嘿哟1 小时前
Python爬虫数据存储:MySQL实战教程
1024程序员节
正经教主1 小时前
【Trae+AI】和Trae学习搭建App_02:后端API开发
学习·app·1024程序员节
岑梓铭1 小时前
《考研408数据结构》第六章(5.1+5.2+5.3树、二叉树、线索二叉树)复习笔记
数据结构·笔记·考研·408·1024程序员节