epoll,IO事件通知机制
2012-11-19 16:30
423 查看
epoll 是poll的变种,它可以用来监视大批量的文件描述符集,同时提供两种触发接口方式:边缘触发(edge-triggered)和水平触发(level-trigered),通过使用以下的系统调用来创建和管理epoll实例。
#include<sys/epoll.h>
int epoll_create(int size);
int epoll_create1(int flags);
一个epoll实例可以通过epoll_create()或epoll_create1()函数来创建,这两个函数返回epoll对象的文件描述符,参数size用来告诉内核需要分配的支持事件存储空间,但不需要告诉内核最大的分配存储数目,自从内核2.6.8开始, size参数没有使用意义,但需要是一个大于0的值。
epoll_create1()拓展了epoll_create()的功能,这个函数是最近内核(2.6.27)新加入的。flags可以是EPOLL_CLOEXEC值。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll_ctl系统调用用来对epfd epoll实例进行操作。op操作类型值包括:
EPOLL_CTL_ADD,注册目标文件描述符fd到epfd epoll 实例, event是fd相关联的事件;
EPOLL_CTL_MOD,修改目标文件描述符fd的event值;
EPOLL_CTL_DEL,从epfd里删除fd, event设置为NULL;
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,关联的文件可写;
EPOLLRDHUP,流socket端关闭连接;
EPOLLPRI,紧急数据(urgent data)可读;
EPOLLERR,关联文件错误发生;
EPOLLHUP,关联文件结束;
EPOLLET,使用边缘触发;
EPOLLLT,使用水平触发;
epoll_ctl调用成功返回0,失败返回-1,并且设置errno。
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
当epfd epoll实例设置好后,调用epoll_wait函数进入监视阶段,events用来存放满足的时间。
边缘触发(Edge-Triggered,EPOLLET)和水平触发(Level-Triggered,EPOLLLT)是epoll支持的两种触发方式。假如epoll监听的文件描述符接收到2K的数据,epoll_wait会返回,并保存事件到events数组中,接着程序使用read系统调用从fd中读取1K数据,则在fd的缓存buffer中还剩下1K的数据未读,这个时候使用LT关联的文件会再次告诉epoll有数据可读,而使用ET方式关联的则不会再次通知。
在通常的使用中ET触发模式常常跟nonblocking文件描述符关联,建议使用ET模式的程序使用以下流程:
1、于非阻塞方式打开文件描述符;
2、调用read或者write函数知道它们返回EAGAIN错误。
Example:
do_use_fd()函数反复的read操作,直到返回EAGAIN后退出该函数。
#include<sys/epoll.h>
int epoll_create(int size);
int epoll_create1(int flags);
一个epoll实例可以通过epoll_create()或epoll_create1()函数来创建,这两个函数返回epoll对象的文件描述符,参数size用来告诉内核需要分配的支持事件存储空间,但不需要告诉内核最大的分配存储数目,自从内核2.6.8开始, size参数没有使用意义,但需要是一个大于0的值。
epoll_create1()拓展了epoll_create()的功能,这个函数是最近内核(2.6.27)新加入的。flags可以是EPOLL_CLOEXEC值。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll_ctl系统调用用来对epfd epoll实例进行操作。op操作类型值包括:
EPOLL_CTL_ADD,注册目标文件描述符fd到epfd epoll 实例, event是fd相关联的事件;
EPOLL_CTL_MOD,修改目标文件描述符fd的event值;
EPOLL_CTL_DEL,从epfd里删除fd, event设置为NULL;
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,关联的文件可写;
EPOLLRDHUP,流socket端关闭连接;
EPOLLPRI,紧急数据(urgent data)可读;
EPOLLERR,关联文件错误发生;
EPOLLHUP,关联文件结束;
EPOLLET,使用边缘触发;
EPOLLLT,使用水平触发;
epoll_ctl调用成功返回0,失败返回-1,并且设置errno。
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
当epfd epoll实例设置好后,调用epoll_wait函数进入监视阶段,events用来存放满足的时间。
边缘触发(Edge-Triggered,EPOLLET)和水平触发(Level-Triggered,EPOLLLT)是epoll支持的两种触发方式。假如epoll监听的文件描述符接收到2K的数据,epoll_wait会返回,并保存事件到events数组中,接着程序使用read系统调用从fd中读取1K数据,则在fd的缓存buffer中还剩下1K的数据未读,这个时候使用LT关联的文件会再次告诉epoll有数据可读,而使用ET方式关联的则不会再次通知。
在通常的使用中ET触发模式常常跟nonblocking文件描述符关联,建议使用ET模式的程序使用以下流程:
1、于非阻塞方式打开文件描述符;
2、调用read或者write函数知道它们返回EAGAIN错误。
Example:
#define MAX_EVENTS 10 struct epoll_event ev, events[MAX_EVENTS]; int listen_sock, conn_sock, nfds, epollfd; /* Set up listening socket, 'listen_sock' (socket(), bind(), listen()) */ epollfd = epoll_create(10); if (epollfd == -1) { perror("epoll_create"); exit(EXIT_FAILURE); } ev.events = EPOLLIN; ev.data.fd = listen_sock; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) { perror("epoll_ctl: listen_sock"); exit(EXIT_FAILURE); } for (;;) { nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_pwait"); exit(EXIT_FAILURE); } for (n = 0; n < nfds; ++n) { if (events .data.fd == listen_sock) { conn_sock = accept(listen_sock, (struct sockaddr *) &local, &addrlen); if (conn_sock == -1) { perror("accept"); exit(EXIT_FAILURE); } setnonblocking(conn_sock); ev.events = EPOLLIN | EPOLLET; ev.data.fd = conn_sock; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) { perror("epoll_ctl: conn_sock"); exit(EXIT_FAILURE); } } else { do_use_fd(events .data.fd); } }
do_use_fd()函数反复的read操作,直到返回EAGAIN后退出该函数。
相关文章推荐
- Linux IO复用--epoll机制
- nginx中的事件响应机制(以epoll为例)
- epoll事件处理机制详解
- DirectShow中的事件通知机制
- 事件触发机制:Poll,Select和Epoll实现原理分析
- 事件处理机制之epoll
- DirectShow之事件通知机制(转)
- 实现一个简单的事件订阅通知机制(Observer模式实现)
- 很幽默的讲解六种Socket IO模型 Delphi版本(自己Select查看,WM_SOCKET消息通知,WSAEventSelect自动收取,Overlapped I/O 事件通知模型,Overlapped I/O 完成例程模型,IOCP模型机器人)
- DirectShow中的事件通知机制
- 文章6:Nginx中的Epoll事件处理机制
- JAVA的事件通知机制
- DirectShow中的事件通知机制
- 深入源码-spring事件通知机制详解
- DirectShow开发快速入门之事件通知机制
- 模型设计与实践---(六)重叠IO,事件通知(Overlap Event)
- epoll事件处理机制详解
- 文章6:Nginx中的Epoll事件处理机制
- Effective C# 学习笔记(二十五)以事件机制来实现通知
- 重叠IO之事件通知模型