高并发服务的核心机制——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: 文件描述符。
      • u32 和 u64: 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.
只支持非阻塞的读写

相关推荐
dingdingfish15 分钟前
TLPI 第49章 读书笔记:Memory Mapping
linux·mmap·munmap·tlpi·msync
EVEN-091328 分钟前
Linux-进程(2)
linux·运维·服务器
u01090535932 分钟前
(永久免费)树莓派 / 香橙派等开发板,安装神卓互联巴比达内网穿透安装教程(Linux ARM 版 V9.4.1)
linux·运维·arm开发
Linux_cy33 分钟前
服务器管理方案选型:面板 / SSH 客户端 / 桌面型客户端怎么选
java·linux·运维·服务器·ssh·可视化·gmssh
可乐_不渴1 小时前
【Linux】 进程虚拟地址空间
java·linux·javascript
byte轻骑兵1 小时前
hcitool 工具:HCI 层指令实操 + 源码中指令的封装逻辑
linux·aiot·bluez·电脑蓝牙·嵌入式蓝牙
qeen871 小时前
【Linux】磁盘读写文件原理及文件系统基本概念介绍
linux·运维·服务器·笔记·学习
Rabitebla1 小时前
【Linux 底层原理】工具篇 (三):gcc/g++ 编译工具、动静态库与编译原理
linux·运维·服务器·笔记·学习
进击的荆棘1 小时前
Linux系统——进程信号
linux·运维·服务器·信号
知已难寻1 小时前
第 5 篇 · 云原生生态与实践:微服务、DevOps、可观测性与 Serverless
大数据·linux·服务器·微服务·云原生·云计算·devops