Android通信之 Epoll

Epoll

无论是从设备节点中获取原始输入事件还是从inotify对象中读取文件系统事件,都面临一个问题,就是这些事件都是偶发的。也就是

说,大部分情况下设备节、inotify对象这些文件描述符中都是无数据可读的,同事有希望有事件到来时可以尽快地对事件做出反应。为

解决这个问题,我们不希望不断地轮询这些描述符,也不希望为每一个描述符创建一个单独的线程进行阻塞时在读取,因为这都会导致资

源被极大的浪费。

此时最佳的办法是使用Epoll机制。Epoll机制可以使用一次等待监听多个描述符的可读/可写状态。等待返回时携带了可读的描述符或

者自定义的数据,使用者据此读取所需的数据后可以再次进入等待。因此不需要为每一个描述符创建对的线程进行阻塞读取,避免了资源浪

费的同时又可以获得较快的响应速度。

Epoll机制的接口:

int epoll_create(int max_fds);

创建一个epoll对象的描述符,之后对epoll的操作均使用这个描述符完成,参数max_fds表示此epoll对象可以监听的描述符的最大数量

int epoll_ctl(int epfd, int op, int fd, struct epoll_event* events);

用于管理注册事件的函数,这个函数可以增加/删除/修改事件的注册

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

用于等待事件的到来。当此函数返回时,events数组参数中将会包含产生事件的文件描述符

int epoll_pwait(int, struct epoll_event*, int, int, const sigset_t*);

以监控若干描述符可读事件为例介绍epoll的用法

创建epoll对象

int epfd;

// Epoll FD list size hint.
static const int EPOLL_SIZE_HINT = 8;

epfd = epoll_create(EPOLL_SIZE_HINT);

填充epoll_event结构体

为每一个需监控的描述符填充epoll_event结构体,以描述监控事件,并通过epoll_ctl()函数将此描述符与epoll_event结构体注册

进epoll对象

epoll_event结构体:

struct epoll_event {
  uint32_t events; /* 事件掩码,指明需要监听的事件种类 */
  epoll_data_t data;   /* 使用者自定义的数据,当次事件发生时,该数据将原封不懂的返回给使用者*/
} ;

epoll_data_t联合体的定义如下,当然,同一时间使用者只能使用一个字段

typedef union epoll_data {
  void* ptr;
  int fd;
  uint32_t u32;
  uint64_t u64;
}

epoll_event结构中的events字段是一个事件掩码,用以子明需要监听的事件种类,同INotify一样,掩码的每一位代表一种事件。

常用的事件有EPOLLIN(可读)、EPOLLOUT(可写)、EPOLLERR(描述符发生错误)、EPOLLHUP(描述符被挂起)等

data字段是一个联合体,它让使用者可以将一些自定义的数据加入事件通知中,当此事件发生是,用户设置的data字段将会返回给使

用者。在实际使用中经常设置epoll_event.data.fd为需要监听的文件描述符,事件发生是便可以根据epoll_event_data.fd得知

引发事件的描述符。当然,也可以设置epoll_event.data.fd为其他便于识别的数据。

填充epoll_event的方法如下:

    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN | EPOLLERR | EPOLLHUP; //监听描述符可读以及出错的事件
    eventItem.data.fd = listeningFd; //填写自定义数据为需要监听的描述符

使用epoll_ctl将事件注册进epoll对象

/**
   epfd是由epoll_create函数所创建的epoll对象的描述符
   op表示 EPOLL_CTL_ADD/DEL/MOD三种操作,分别表示增加/删除/修改注册事件
   fd表示需要监听的描述符
   event参数是描述监听事件的详细信息的epoll_event结构体
 */
result = epoll_ctl(epfd, EPOLL_CTL_ADD, listeningFd, &eventItem);

重复这个步骤可以将多个文件描述符的多种事件监听注册到epoll对象中。

使用epoll_wait()函数等待事件

epoll_wait()函数将会是调用者陷入等待状态,知道其注册的事件之一发生之后才返回,并且携带刚刚发生的事件的详细信息

/**
   epfd是由epoll_create函数所创建的epoll对象的描述符
   events参数是一个epoll_event的数组,此函数返回时,事件的信息将被填充至此
   maxevents表示此次调用最多可以获取多少个事件,当然,events参数必须能足够容纳这么多事件
   timeout表示等待超时的时间
 */
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);

处理事件

epoll_wait()返回后,便可以根据events数组中所保存的所有epoll_events结构体的events字段与data字段识别事件的类型与来源

Epoll使用总结

通过epoll_create()创建epoll对象

为需要监听的描述符填充epoll_event结构体

使用epoll_ctl将事件注册进epoll对象

使用epoll_wait()函数等待事件

根据epoll_wait()返回的epoll_events结构体数组判断事件的类型与来源并进行处理

继续使用epoll_wait()等待新事件发生

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值