epoll 详解:Linux 高性能 I/O 多路复用机制
epoll
是 Linux 特有的 I/O 事件通知机制,专为高并发场景设计,解决了 select
/poll
的性能瓶颈。以下是其核心特性和使用方法:
1. epoll 的核心优势
特性 | select/poll | epoll |
---|---|---|
时间复杂度 | O(n),需遍历所有 FD | O(1),仅返回就绪的 FD |
FD 数量限制 | 有限(默认1024) | 理论无上限(受系统内存限制) |
事件触发方式 | 水平触发(LT) | 支持水平触发(LT)和边缘触发(ET) |
内核数据拷贝 | 每次调用需拷贝 FD 集合到内核 | FD 仅注册一次,无需重复拷贝 |
2. epoll API
(1) epoll_create()
创建 epoll 实例,返回一个文件描述符(epfd)。
int epfd = epoll_create1(0); // Linux内核2.6.27+推荐使用
(2) epoll_ctl()
向 epoll 实例添加/修改/删除监控的 FD。
struct epoll_event ev;
ev.events = EPOLLIN; // 监听可读事件
ev.data.fd = sockfd; // 关联的socket
// op: EPOLL_CTL_ADD/MOD/DEL
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
(3) epoll_wait()
等待事件就绪,返回就绪的 FD 数量。
struct epoll_event events[MAX_EVENTS];
int nready = epoll_wait(epfd, events, MAX_EVENTS, timeout);
for (int i = 0; i < nready; i++) {
if (events[i].events & EPOLLIN) {
int fd = events[i].data.fd;
handle_read(fd); //处理可读事件
}
}
3. epoll 的工作模式
(1) Level-Triggered (LT,水平触发)
- 默认模式,类似
select/pool
。
- 特点:只要 FD 处于可读/可写状态,每次调用
epol_wait()
都会通知应用层。
- 适用场景:编程简单,适合需要稳定处理数据的场景。
(2) Edge-Triggered (ET,边缘触发)
- 高效模式,仅在状态变化时触发一次通知。
- 特点:必须一次性处理完所有数据(循环读写直到
EAGAIN
),否则会丢失后续事件。
- 要求:必须将 FD设为非阻塞模式:
ev.events = EPOLLIN | EPOLLET; // ET模式 +非阻塞IO
fcntl(sockfd, F_SETFL, fcntl(sockfd,F_GETFL)|O_NONBLOCK);
- 适用场景:高性能服务器(如Nginx)。
4. epol的使用示例
(1) TCP服务器核心代码片段
//初始化epll并添加监听socket
int listen_fd=socket(...);
bind(listen_fd,...);listen(listen_fd,...);
int epll_fd=epll_create1(0);
struct epll_event ev;
ev.events=EPOLLIN;
ev.data.fd=listen_fd;
epll_ctrl(epll_fd,EPOLL_CTL_ADD,listen_fd,&ev);
while(1){
int nready=epll_wait(epll_fd,eents,-1);//阻塞等待
for(int i=0;i<nready;i++){
if(eents[i].data.fd==listen_fd){//新连接到达
int conn_fa=accept(...);
set_nonblocking(conn_fa);//设为非阻塞
ev.events=EPOLLIN|EPOLLET;//ET模式
ev.data.fa=conn fa;
epl l_ctrl(e p ll _f d,E PO LL _C TL _A DD ,co nn _f d,&e v );
}else{//已连接socket有数据
handle_client_request(e ents [i ].da ta .f d );
}
}
}
(2) ET模式下读取数据的正确方式
void handle_client_request(int fd){
char buf[1024];
while(1){//循环读取直到EAGAIN
ssize_t n=read(fa,buf,sizeof(buf));
if(n>0){
process_data(buf,n);//处理数据
}else if(n==0||errno==EAGAIN){
break;//无更多数据或对端关闭连接
}else{
perror("read error");
close(fa);break;
}
}
}
##5.e poll vs select/pool对比总结
select/pool | lte poll | |
---|---|---|
性能随着FD增长而下降明显适用于低并发环境适用于高并发环境 |
##6.学习建议
如果想深入掌握网络编程和高性能服务开发技术可以学习零声教育提供的《C++后端开发》课程涵盖以下内容:
- 网络协议栈深度解析(TCP/IP、HTTP/QUIC)
- 异步IO框架设计(e poll协程、io _uring)
- 分布式中间件开发(RPC、消息队列)
课程链接:https://www.Ovoice.com/uiwebsite/html/courses/v13.html
通过系统化学习可以快速提升技术水平胜任互联网大厂高级开发岗位!
内容由零声教学AI助手提供,问题来源于学员提问