前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Epoll 机制

Epoll 机制

作者头像
DragonKingZhu
发布2020-03-24 17:20:47
6690
发布2020-03-24 17:20:47
举报
文章被收录于专栏:Linux内核深入分析

描述

epoll 是poll系统调用的升级版。可以用做单边沿(level-triggered)和双边沿(edge-triggered)的两种工作模式,同样也可以用于检测多个文件描述符。

API

  • epoll_create(int size)

用于创建一个epoll的实例对象。参数size代表可以一次性检测的文件对象的个数。返回值是epoll 实例对象的文件描述符,次描述符用于后续的epoll_ctl和epoll_wait函数中,当没有对象检测的时候,需要使用close系统调用关系该文件描述符,因为epoll实际上也会占用用一个fd的。

  • epoll_ctl(int epfd, int op, int fd, struct epoll_event* event)

用于注册要检测的对象以及检测的事件。 epfd代表的是epoll的实例对象,也就是epoll_create的返回值。op代表的几种操作,如下:

EPOLL_CTL_ADD: 注册一个new的fd对象到epoll实例中。

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

EPOLL_CTL_DEL: 从epoll检测的列表中remove掉fd。

event就是代表具体要检测的事件类型,详细信息如下:

struct epoll_event结构体定义:

代码语言:javascript
复制
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成员,代表具体检测的事件类型:

代码语言:javascript
复制
EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
  • epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout)

该系统调用用于等待检测对象的事件发生。 events具体返回具体的发生的事件内容,maxevents用于告知允许最大的事件数量,timout当然也就是超时时间,-1代表一直等待不超时。返回值代表发生事件需要处理的数据,返回值为0代表timeout。

实例分析

代码语言:javascript
复制
#include <sys/epoll.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


#define EPOLL_INSTANCE_SIZE (8)
#define EPOLL_EVENTS_SIZE   (8)


int main(int argc, char** argv)
{

    int epfd;
    int i = 0;
    int events;
    struct epoll_event eventItem[EPOLL_EVENTS_SIZE];
    char buf[512];

    /*usage*/
    if(argc < 2 )
    {
        printf("Usage: %s <file1> <file2> ...\n", argv[0]);
        return -1;
    }

    /*创建epoll实例对象*/
    epfd = epoll_create(EPOLL_INSTANCE_SIZE);
    if(epfd == -1)
    {
        printf("epoll_create error!\n");
        return -1;
    }
    
    /*添加检测实例对象*/
    for(i = 1; i < argc; i++)
    {
        int fd;
        struct epoll_event event;

        fd = open(argv[i], O_RDWR);                
        event.events = EPOLLIN;
        event.data.fd = fd;
        epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
    }
 
    while(1)
    { 
        /*等待事件发生*/
        events = epoll_wait(epfd, eventItem, EPOLL_EVENTS_SIZE, -1);
        for(i = 0; i < events; i++)
        {
            int len = read(eventItem[i].data.fd, buf, 512);
            buf[len] = '\0';
            printf("read buf is %s\n",buf);
        }
    }
    
    return 0;
}

测试结果:

1. 编译代码

代码语言:javascript
复制
gcc epoll.c -o epoll

2. 在tmp创建下创建3个fifo文件

代码语言:javascript
复制
mkfifo tmp/1 tmp/2 tmp3

3. 使用epoll在后台检测

代码语言:javascript
复制
./epoll tmp/1 tmp/2 tmp/3 &

可以从/proc/epoll进程的pid/fd中看到详细信息

4. echo 数据到 tmp/1中查看结果

代码语言:javascript
复制
test$ echo 111 > tmp/1
read buf is 111
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 描述
  • API
  • 实例分析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档