Linux epoll I/O 多路复用快速使用流程 2025-06-26

//头文件
#include  <sys/epoll.h>
//创建epoll实例
int epfd = epoll_create(>0);//成功返回的是文件描述符错误返回的是-1
//在epoll实例中添加需要检测的节点,
struct epoll_event ev;
ev.events=EPOLLIN;//检测lfd的读事件(基础有三个都是对应文件描述符的事件(读事件、写事件、错误事件)man epoll_ctl可以看到)
ev.data.fd=lfd;//要操作的文件描述符 这个其实设计的联合体 有别的可以选 看man
//使用epoll_ctl操作epoll实例
/*
    EPOLL_CTL_ADD:注册新的 fd
    EPOLL_CTL_MOD:修改已注册的 fd
    EPOLL_CTL_DEL:删除 fd
*/
if (epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {
    perror("epoll_ctl: add");
    exit(EXIT_FAILURE);
}
//循环等待事件发生
int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);//通常在while包装下
//timeout 设置-1表示无线等待

epoll默认是水平模式(LT模式),只提示一次的边沿模式(ET模式)更高效。
水平模式:只要检测的文件描述符事件缓冲区有数据就会epoll_wait阻塞;
边沿模式:当对应的文件描述符被放到epoll检测中的事件,只有有新的数据到达缓冲区才会epoll_wait解除阻塞。
(只会通知一次,不会管缓冲区的数据是否有被读出)

//边沿模式的设置(默认就是水平模式)
ev.events=EPOLLIN|EPOLLET;
//因为只通知一次就需要一次性将所有的数据都处理完毕
//方法是开辟足够大的缓冲区(在内存上)或者循环接收
//二者都是有弊端的,一个是占用的内存可能过大
//另一个是默认的套接字通信中的read/write等相关函数都是阻塞的
//也就是说当我们不知道缓冲区有多少数据,我们一直recv,直到缓冲区为空,缓冲区会阻塞等待(这个线程就会阻塞的)
//所以需要修改这个文件描述符的属性,是其是非阻塞的

修改文件描述符的属性,是其是非阻塞的

#include <fcntl.h>
//这里cfd是要操作的文件描述符
int flag = fcntl(cfd,F_GETFL);//F_GETFL意思是获取到当前文件描述符的属性
flag |=O_NONBLOCK;//添加非阻塞属性
fcntl(cfd,F_SETFL,flag);

也可以使用

rt = fcntl(m_tickleFds[0], F_SETFL, O_NONBLOCK);

但这种方式会覆盖所有其他标志(如果前面有添加别的属性的话)
fcntl函数讲解
或者看man文档


还没完...
设置为非阻塞后,当缓冲区为空后第一次读会读出来空
第二次就会出现错误:

rec error: Resource temporarily unavailable
man recv
/return value (man文档搜索这个)

如果是EAGAIN就代表缓冲区已经读完了然后我们就可以break了

#include <errno.h>
if(errno==EAGAIN)
{
  break;
}else
{
  perror/assert 看需求
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容