嵌入式Linux系统epoll机制

1 什么是epoll

上一章节中,我们创建了一个tcp server和client,进行数据的收发,而数据收发的过程是阻塞的,如调用到的recv函数,没有收到数据前一直卡住不会往下去执行其它代码。操作tcp也好,读写文件也罢,或者其它文件描述符,本质都是对I/O资源的操作;但对于什么时候来数据可以进行读取,其它方法比如阻塞,线程池并发,select多路复用这些我们一概忽略,基本现在产品开发可以用epoll代替。

简单来说,epoll使用红黑树的数据结构去监听并维护文件描述符。通过事件的方式告诉应用层去处理,从而实现异步事件通知的功能。

基本函数就3个:

epoll_create1: 创建一个epoll实例,文件描述符。

epoll_ctl: 将监听的文件描述符添加到epoll实例中,实例代码为将标准输入文件描述符添加到epoll中。

epoll_wait: 等待epoll事件从epoll实例中发生, 并返回事件以及对应文件描述符。

2 实例

本章节代码在:…\tutorials\Patchs\2. epoll实例

首先我们调用epoll_create1创建一个实例:

int epoll_fd = epoll_create1(0);

然后把要监听的文件描述符加入进去,调用epoll_ctl 函数:

假设要监听的是fd:epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);

参数说明:

第一个参数是epoll实例id,

第二个参数是选项,可选值:

EPOLL_CTL_ADD:注册新的fd到epfd中;

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

EPOLL_CTL_DEL:从epfd中删除一个fd;

第三个参数是要监听的文件描述符,

第四个参数类型(epoll_event)如下:

 

  1. struct epoll_event  
  2. {  
  3.   uint32_t events;  /* Epoll events */  
  4.   epoll_data_t data;    /* User data variable */  
  5. };  
  6.  
  7. typedef union epoll_data  
  8. {  
  9.   void *ptr;  
  10.   int fd;  
  11.   uint32_t u32;  
  12.   uint64_t u64;  
  13. } epoll_data_t;  

epoll_data一般用来存储用户自己的数据,然后在监听到事件时可以取到这部分数据;epoll_event中的events取值如下:

EPOLLIN : 对应的文件描述符可以读(包括对端SOCKET正常关闭);

EPOLLOUT: 对应的文件描述符可以写;

EPOLLPRI: 对应的文件描述符有紧急的数据可读;

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

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

EPOLLET: 将 EPOLL设为边缘触发(Edge Triggered)模式(默认为水平触发);

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

直接上代码:

epoll_ctl添加后,只需要不断调用epoll_wait就可以完成描述符的监听了,有事件时,返回值会大于0。图中//TODO表示用户需要完成的业务代码,比如我们处理如下:

这里只是实例代码,因此没有太多的容错处理(后面直接会提供一个商用的框架给大家参考),编译运行结果:

==================================================================================================================================

EPOLL机制轻松就学习完啦,就是这样Easy!!

如果觉得对您有帮助并想进一步深入学习交流可以扫描以下微信二维码或加入QQ群:928840648

欢迎共同学习成长,有一群爱学习的小伙伴一起勉励!!一起加油!!也可点击

 

笔者基于嵌入式系统框架内容如下整理编辑: