epoll接口函数
头文件: #include<sys/epoll.h>
可以通过man epoll查看对应的帮助信息
最大描述符限制:/proc/sys/fs/epoll/max_user_watches
创建epoll实例
|
|
epoll_create中,size只是给内核的一个维数提示,并不是队列中的最大数,Now days, size is ignored since Linux 2.6.8
epoll_create1中flag取值如下:
- 0:epoll_create1 == epoll_create (size argument is dropped)
- EPOLL_CLOEXEC:含义同open函数的O_CLOEXEC选项;当执行execve创建新进程时,打开的描述符自动关闭
p.s: 当使用完毕时,需要调用close关闭epoll实例句柄管理epoll事件
|
|
参数说明:
- epfd: epoll_create返回的epoll实例
- op: 对应的操作
- fd: 监听的fd
- event: 监听的事件
其中op取值如下: - EPOLL_CTL_ADD:添加监听的事件
- EPOLL_CTL_DEL:删除监听的事件
- EPOLL_CTL_MOD:修改监听的事件
struct epoll_event定义如下:
|
|
其中events可以包含以下事件类型:
- EPOLLIN: 描述符可读
- EPOLLOUT: 描述符可写
- EPOLLRDHUP(since Linux 2.6.17): 流套接字对端关闭连接或者关闭写端
- EPOLLPRI: 紧急数据可读
- EPOLLERR: 描述符发生错误,该事件由内核一直监听(比如connect套接字失败会返回EPOLLERR)
- EPOLLHUP: 文件秒杀符被中断,该事件由内核一直监听
- EPOLLET: 开启边缘触发,默认是水平触发
- EPOLLONESHOT: 一个事件发生并读取之后,fd自动不再监控;若要重新监控需要使用EPOLL_CTL_MOD重新设置
返回值: 成功返回0,失败返回-1并设置errno等待epoll事件
|
|
参数说明:
- epfd: epoll_create返回的epoll实例
- events: 存储epoll_event的数组地址
- maxevents: 最大事件的数量,需>0
- timeout: 等待的最长时间
返回值:
成功时返回就绪的监听文件描述符数;当超出timeout指定的时间后如果无就绪的文件描述符,返回0;发生错误时返回-1并设置errno
另外,Linux kernel 2.6.19 引入了epoll_pwait,可以在等待时设置信号掩码,其使用方式类似pselect
some problems:
- epoll 怎么判断是connect请求还是有数据可读?
ans: 判断events[i].data.fd == listen_fd - read 返回值说明:
- return -1 and errno == EAGAIN: 数据已经读完,没有可读数据
- return 0: end of file,对端关闭连接
关于水平触发(Level-Triggered)和边缘触发(Edge-Triggered)
当缓冲区有数据可读时,ET会触发一次事件,之后就不会再触发;而LT只要我们没有读完缓冲区的数据,事件就会一直触发。
推荐使用的epoll ET方式如下:
- 设置fd为非阻塞
- 当调用read或write读写时,在其返回-1,且errno == EAGAIN 后再调用epoll_wait等待
tips:
ET模式只能用于设置了O_NONBLOCK的fd,而LT则同时支持同步及异步。如果将ET模式应用与阻塞情况,将出现如下问题:
当对端send 2 byte数据,而服务端只读取了1 byte后再去调用epoll_wait,这时将不产生读事件。直到对端又有数据发送过来,epoll_wait才会再次返回
补充:
Q:当又有事件产生时会怎么样,原来的数据还在吗?
A:原来的数据还在socket缓冲区epoll实例
epoll使用参考:
- 服务端代码:How to use epoll? A complete example in C, it’s a well write paper.
|
|
- 客户端代码:
|
|
mac下的epoll
mac os不支持epoll,其使用kqueue实现(类似epoll),头文件 sys/event.h
link:https://zhuanlan.zhihu.com/p/21375144
epoll源码实现
参考博客:Linux epoll 详解