epoll是什么
epoll
是一种I/O
多路复用技术的一种,相比于poll
及select
有改进。
epoll
的优点有以下:
- 没有最大并发连接的限制,可打开文件数量远大于$2^{11}$
epoll
不在乎连接总数,只和当前「活跃」的连接数量相关,因此相比于poll
和select
,效率明显提升epoll
使用了「共享内存」,因此省略了「内存拷贝」,进一步提升了效率
内核空间与用户空间
-
内核空间是操作系统内核运行的区域,包含了操作系统内核代码、数据结构和设备驱动程序等
-
用户空间是用户应用程序运行的区域,包括用户应用程序代码、数据和堆栈等
以Linux操作系统为例,将最高的1G分配给内核空间,剩余3G分配给用户空间。
而每个进程可以通过系统调用进入内核,因此Linux内核由系统内所有进程共享,每个进程拥有4G虚拟空间。
为什么要区分内核空间与用户空间
CPU指令中的部分指令很危险,如果错用会导致系统崩溃。因此将指令分级,部分只允许操作系统使用。
内核态与用户态
- 当进程/线程运行于内核中是内核态;运行于用户空间中是用户态
- 内核态下,CPU可以执行任何指令/运行的代码不受限制/自由访问地址/端口
- 用户态下,代码收到CPU很多检查,例如只能访问部分空间
epoll函数
epoll
主要包含三个函数epoll_create/epoll_ctl/epoll_event
。
包含这些函数的头文件为<sys/epoll.h>
。
fd(File descriptor)
fd
是指文件描述符,是一个非负整数,本质上是一个索引值,类似一个地址,能直接获取某个文件。
什么时候拿到fd
当打开一个文件时,内核向进程返回一个文件描述符,后续打开这个文件则只需要用文件描述符标识该文件,作为参数传进read/write
。
fd的范围
0/1/2
这3个值有特殊含义,分别是标准输入/标准输出/标准错误。
文件描述符的范围是[0,OPEN_MAX-1]
,代表默认最多可以打开多少个文件。
ulimit -n
256
使用ulimit -n
命令查询得到256
,说明同时最多可以打开256
个文件。
epoll_create
int epoll_create(int size);
epoll_create
函数是用来创建epoll
文件描述符,用于后续的epoll
操作。

epoll_ctl
int epoll_ctl(int epfd, int op, int fd, struct epoll_event &event);
epoll_ctl
函数是用于增加、删除、修改epoll
事件的函数。epoll
事件存储于内核epoll
结构体红黑树中。
epfd: epoll文件描述符
op: 操作码
EPOLL_CTL_ADD: 插入事件
EPOLL_CTL_DEL: 删除事件
EPOLL_CTL_MOD: 修改事件
fd: 事件绑定的套接字文件描述符
events: 事件结构体
返回值:0/-1(成功/失败)

epoll struct epoll_event
#include <sys/epoll.h>
struct epoll_event {
uint32_t events; // epoll事件
epoll_data_t data;
};
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
epoll事件列表
头文件:<sys/epoll.h>
enum EPOLL_EVENTS
{
EPOLLIN = 0x001, //读事件
EPOLLPRI = 0x002,
EPOLLOUT = 0x004, //写事件
EPOLLRDNORM = 0x040,
EPOLLRDBAND = 0x080,
EPOLLWRNORM = 0x100,
EPOLLWRBAND = 0x200,
EPOLLMSG = 0x400,
EPOLLERR = 0x008, //出错事件
EPOLLHUP = 0x010, //出错事件
EPOLLRDHUP = 0x2000,
EPOLLEXCLUSIVE = 1u << 28,
EPOLLWAKEUP = 1u << 29,
EPOLLONESHOT = 1u << 30,
EPOLLET = 1u << 31 //边缘触发
};
epoll_wait函数
epoll_wait
用于监听套接字事件,可以通过设置超时时间timeout
来控制监听行为是阻塞模式还是超时模式。
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
参数:
epfd: epoll文件描述符
events: epoll事件数组
maxevents: epoll事件数组长度
timeout: 超时时间
小于0: 一直等待
等于0: 立即返回
大于0: 等待超时时间返回,单位毫秒
返回值:
小于0: 出错
等于0: 超时
大于0: 返回就绪事件个数
ET与LT
两种模式区别在于触发方式不同。LT
模式(水平触发)会持续通知应用程序,直到所有事件被处理完毕;ET
模式(边沿触发)只在事件发生变化的时侯通知应用程序,即只通知一次,不管事件是否已经被处理。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)