epoll 基本知识与使用

https://blog.csdn.net/qq_35721743/article/details/86742508

 

epoll 最大的好处在于它不会随着监听 fd 数目的增长而降低效率。

epoll 的接口,一共有三个函数, 都在头文件 #include <sys/epoll.h> 里。

1. 创建 epoll 句柄

  int epfd = epoll_create(intsize);

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

函数声明: int epoll_create(int size)

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

2. 将被监听的描述符添加到epoll句柄或从epoll句柄中删除或者对监听事件进行修改

函数声明:int epoll_ctl( int epfd, int op, int fd, struct epoll_event* event )

返回值:如果调用成功返回0,不成功返回-1.

该函数用于控制某个 epoll 文件描述符上的事件,可以注册事件、修改事件、删除事件。

参数:

epfd : 由 epoll_create 生成的 epoll 专用的文件描述符;

op : 要进行的操作,例如注册事件。可能的取值有:

                            EPOLL_CTL_ADD  :  注册新的 fd 到 epfd 中

                            EPOLL_CTL_MOD : 修改已经注册的 fd 的监听事件

                            EPOLL_CTL_DEL : 从 epfd 中删除一个 fd

fd : 关联的文件描述符,需要监听的 fd .

event : 指向 epoll_event 的指针, 告诉内核需要监听什么事件 , struct epoll event 结构如下:

struct epoll_event{
    __uint32_t events; // Epoll events: EPOLLIN,EPOLLOUT,EPOLLPRI,EPOLLERR,EPOLLHUP,EPOLLET,EPOLLONESHOT
    epoll_data_t data;  // User data variable
};

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

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

EPOLLIN : 触发该事件,表示对应的文件描述符上有可读数据。 (包括对端 SOCKET 正常关闭)

EPOLLOUT : 触发该事件,表示对应的文件描述符上可以写数据;

EPOLLPRI : 表示对应的文件描述符上有紧急的数据可读(这里应该表示有带外数据到来);

EPOLLERR : 表示对应的文件描述符发生错误;

EPOLLHUP : 表示对应的文件描述符被挂断;

EPOLLET : 将 EPOLL 设为 边缘触发 (Edge Triggered) 模式,这是相对于水平触发(Level Triggered)来说的。

EPOLLONESHOT : 只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里。

如:

struct epoll_event ev;
ev.data.fd = listenfd; // 设置与要处理的事件相关的文件描述符
ev.events = EPOLLIN | EPOLLOUT; // 设置要处理的事件类型
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev); // 注册 epoll 事件

 

3. 等待事件触发, 当超过 timeout 还没有事件触发时,就超时

int epoll_wait(  int epfd,   struct epoll_event * events,   int maxevents,   int timeout  );

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

参数:

epfd : 由 epoll_create 生成的epoll专用的文件描述符;

events : 用于回传待处理的事件的数组,从内核得到事件的集合

maxevents : 每次能处理的事件数, 告知内核这个events有多大(数组成员的个数),这个maxevents 的值不能大于创建epoll_create()时候的size。

timeout : 等待 IO 事件发生的超时值; -1相当于阻塞, 0相当于非阻塞

epoll_wait 运行的原理是: 等待注册在 epfd 上的 socket fd 的 事件发生,如果发生,则将发生的fd 和事件保存在 events里,并将epfd上该fd的事件清空。如果需要继续监听该fd,则需要使用EPOLL_CTL_MOD 添加需要监听的事件。因为没有清空epfd上的fd,所以不需要使用EPOLL_CTL_ADD.

 

最后,水平触发(LT)是默认的工作模式,适合与阻塞和非阻塞socket, 错误率小。边缘出发(ET)是高速工作模式,只适用于非阻塞socket。

 

 

 

 

 

 

 

 

 

     

posted @ 2019-11-26 09:32  小荷才楼尖尖角  Views(371)  Comments(0Edit  收藏  举报