高并发服务的核心机制——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.
只支持非阻塞的读写

相关推荐
木子Linux11 分钟前
【Linux打怪升级记 | 问题01】安装Linux系统忘记设置时区怎么办?3个方法教你回到东八区
linux·运维·服务器·centos·云计算
mit6.82417 分钟前
Ubuntu 系统下性能剖析工具: perf
linux·运维·ubuntu
鹏大师运维19 分钟前
聊聊开源的虚拟化平台--PVE
linux·开源·虚拟化·虚拟机·pve·存储·nfs
watermelonoops26 分钟前
Windows安装Ubuntu,Deepin三系统启动问题(XXX has invalid signature 您需要先加载内核)
linux·运维·ubuntu·deepin
滴水之功1 小时前
VMware OpenWrt怎么桥接模式联网
linux·openwrt
ldinvicible2 小时前
How to run Flutter on an Embedded Device
linux
YRr YRr2 小时前
解决Ubuntu 20.04上编译OpenCV 3.2时遇到的stdlib.h缺失错误
linux·opencv·ubuntu
认真学习的小雅兰.2 小时前
如何在Ubuntu上利用Docker和Cpolar实现Excalidraw公网访问高效绘图——“cpolar内网穿透”
linux·ubuntu·docker
zhou周大哥3 小时前
linux 安装 ffmpeg 视频转换
linux·运维·服务器
不想起昵称9293 小时前
Linux SHELL脚本中的变量与运算
linux