[Linux] Linux epoll的用法

Epoll的用法

select与epoll

在旧的Linux中,通常都在使用select来做事件触发,而在新的Linux内核中,开始使用epoll来代替。相比于select,epoll最大的好处就是不会随着监听fd数目的增长而降低效率。

当使用select时,它是采用轮询来处理的,轮询的fd数目越多,耗时越长,而且select同时监听的fd数目有限,通常为1024个,当然,这可以通过修改相关头文件然后对内核进行重新编译来解决。

epoll接口

1. 创建epoll句柄
int epfd = epoll_create(int size);

创建一个epoll句柄,size用来告诉内核这个监听的数目一共多大。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程ID/fd是能够看到这个fd的,所以在使用完epoll后,必须调用close()函数进行关闭,否则可能导致fd被耗尽。

该函数生成一个epoll专用的文件描述符,它其实是在内核申请一空间,用来存放你想关注的socket fd上是否发生以及发生了什么事件,size就是你在这个epoll fd上能关注的最大socket fd数目。

2. 将被监听的描述符添加到epoll句柄或从epoll句柄中删除 或者对监听事件进行修改
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);

该函数用来控制某个epoll文件描述符上的事件,可以注册事件、修改事件和删除事件。其中,epfd为由epoll_create生成的epoll专用的文件描述符;op为要进行的操作注册事件,可能的取值有EPOLL_CTL_ADD注册、EPOLL_CTL_MOD修改、EPOLL_CTL_DEL删除;fd为关联的文件描述符;event为指向epoll_event的指针。

epoll和select的一个不同点就是select()是在监听事件时告诉内核要监听什么类型的事件,而epoll是先注册要监听的事件类型。

这里epoll_ctl的第四个参数为epoll_event类型,其定义如下:

typedef union epoll_data {
  void* ptr;
  int fd;
  __uint32_t u32;
  __uint64_t u64;
} epoll_data_t;

struct epoll_event {
  __uint32_t events; // Epoll events
  epoll_data_t data; // User data variable
};

events可以是以下几个宏的集合:

EPOLLIN             触发该事件,表示对应的文件描述符上有可读数据
EPOLLOUT            触发该事件,表示对应的文件描述符上可以写数据
EPOLLPRI            表示对应的文件描述符有紧急的数据可读
EPOLLERR            表示对应的文件描述符发生错误
EPOLLHUP            表示对应的文件描述符被挂断
EPOLLET             将EPOLL设置为边缘触发模式(Edge Triggered)
EPOLLONESHOT        只监听一次事件,当监听完这次事件之后,如果还需要监听这个socket的话,需要再把这个 socket加入到EPOLL队列里

举个例子:

struct epoll_event ev;
ev.data.fd = listenfd; // 设置与要处理的事件相关的文件描述符
ev.events = EPOLLIN | EPOLLET; // 设置要处理的事件类型
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev); // 注册epoll事件
3. 等待事件触发,当超过timeout还没有事件触发时,就超时
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);

等待事件的产生,类似于select()调用,参数events用来从内核得到事件的集合,maxevents告诉内核这个events有多大(数组成员的个数),这个maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定)。

该函数返回需要处理的事件数目,如返回0表示已超时;返回的事件集合在events数组中,数组中实际存放的成员个数是函数的返回值。

epoll_wait运行的原理是:等待注册在epfd上的socket fd事件的发生,如果发生则将发生的socket fd和事件类型放入到events数组中,并且将注册在epfd上的 socket fd的事件类型清空,所以如果下一个循环你还要关注这个socket fd的话,则需要使用epoll_ctl(epfd, EPOLL_CTL_MOD, listenfd, &ev)来重新设置socket fd的事件类型,这时不用EPOLL_CTL_ADD,因为socket fd并未清空,只是事件类型清空。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值