linux epollWord格式.docx
- 文档编号:15840909
- 上传时间:2022-11-16
- 格式:DOCX
- 页数:35
- 大小:133.51KB
linux epollWord格式.docx
《linux epollWord格式.docx》由会员分享,可在线阅读,更多相关《linux epollWord格式.docx(35页珍藏版)》请在冰豆网上搜索。
第一个参数是epoll_create()的返回值。
第二个参数表示动作,用三个宏来表示:
EPOLL_CTL_ADD:
注册新的fd到epfd中;
EPOLL_CTL_MOD:
修改已经注册的fd的监听事件;
EPOLL_CTL_DEL:
从epfd中删除一个fd;
第三个参数是需要监听的fd。
第四个参数是告诉内核需要监听什么事,structepoll_event结构如下:
[cpp]viewplaincopy
print?
//保存触发事件的某个文件描述符相关的数据(与具体使用方式有关)
typedef
union
epoll_data
{
void
*ptr;
int
fd;
__uint32_t
u32;
__uint64_t
u64;
}
epoll_data_t;
//感兴趣的事件和被触发的事件
struct
epoll_event
events;
/*
Epoll
events
*/
epoll_data_t
data;
User
data
variable
};
//保存触发事件的某个文件描述符相关的数据(与具体使用方式有关)
typedefunionepoll_data{
void*ptr;
intfd;
__uint32_tu32;
__uint64_tu64;
}epoll_data_t;
//感兴趣的事件和被触发的事件
structepoll_event{
__uint32_tevents;
/*Epollevents*/
epoll_data_tdata;
/*Userdatavariable*/
events可以是以下几个宏的集合:
EPOLLIN
:
表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:
表示对应的文件描述符可以写;
EPOLLPRI:
表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:
表示对应的文件描述符发生错误;
EPOLLHUP:
表示对应的文件描述符被挂断;
EPOLLET:
将EPOLL设为边缘触发(EdgeTriggered)模式,这是相对于水平触发(LevelTriggered)来说的。
EPOLLONESHOT:
只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
2.3.3.intepoll_wait(intepfd,structepoll_event*events,intmaxevents,inttimeout);
收集在epoll监控的事件中已经发送的事件。
参数events是分配好的epoll_event结构体数组,epoll将会把发生的事件赋值到events数组中(events不可以是空指针,内核只负责把数据复制到这个events数组中,不会去帮助我们在用户态中分配内存)。
maxevents告之内核这个events有多大,这个
maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。
如果函数调用成功,返回对应I/O上已准备好的文件描述符数目,如返回0表示已超时。
3.epoll工作原理
epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符在系统调用时复制的开销。
另一个本质的改进在于epoll采用基于事件的就绪通知方式。
在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。
Epoll的2种工作方式-水平触发(LT)和边缘触发(ET)
假如有这样一个例子:
1.我们已经把一个用来从管道中读取数据的文件句柄(RFD)添加到epoll描述符
2.这个时候从管道的另一端被写入了2KB的数据
3.调用epoll_wait
(2),并且它会返回RFD,说明它已经准备好读取操作
4.然后我们读取了1KB的数据
5.调用epoll_wait
(2)......
3.1.EdgeTriggered工作模式
如果我们在第1步将RFD添加到epoll描述符的时候使用了EPOLLET标志,那么在第5步调用epoll_wait
(2)之后将有可能会挂起,因为剩余的数据还存在于文件的输入缓冲区内,而且数据发出端还在等待一个针对已经发出数据的反馈信息。
只有在监视的文件句柄上发生了某个事件的时候ET工作模式才会汇报事件。
因此在第5步的时候,调用者可能会放弃等待仍在存在于文件输入缓冲区内的剩余数据。
在上面的例子中,会有一个事件产生在RFD句柄上,因为在第2步执行了一个写操作,然后,事件将会在第3步被销毁。
因为第4步的读取操作没有读空文件输入缓冲区内的数据,因此我们在第5步调用epoll_wait
(2)完成后,是否挂起是不确定的。
epoll工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。
最好以下面的方式调用ET模式的epoll接口,在后面会介绍避免可能的缺陷。
i
基于非阻塞文件句柄
ii
只有当read
(2)或者write
(2)返回EAGAIN时才需要挂起,等待。
但这并不是说每次read()时都需要循环读,直到读到产生一个EAGAIN才认为此次事件处理完成,当read()返回的读到的数据长度小于请求的数据长度时,就可以确定此时缓冲中已没有数据了,也就可以认为此事读事件已处理完成。
3.2.LevelTriggered工作模式
相反的,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll
(2),并且无论后面的数据是否被使用,因此他们具有同样的职能。
因为即使使用ET模式的epoll,在收到多个chunk的数据的时候仍然会产生多个事件。
调用者可以设定EPOLLONESHOT标志,在epoll_wait
(2)收到事件后epoll会与事件关联的文件句柄从epoll描述符中禁止掉。
因此当EPOLLONESHOT设定后,使用带有EPOLL_CTL_MOD标志的epoll_ctl
(2)处理文件句柄就成为调用者必须作的事情。
LT(leveltriggered)是epoll缺省的工作方式,并且同时支持block和no-blocksocket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。
如果你不作任何操作,内核还是会继续通知你
的,所以,这种模式编程出错误可能性要小一点。
传统的select/poll都是这种模型的代表.
ET(edge-triggered)是高速工作方式,只支持no-blocksocket,它效率要比LT更高。
ET与LT的区别在于,当一个新的事件到来时,ET模式下当然可以从epoll_wait调用中获取到这个事件,可是如果这次没有把这个事件对应的套接字缓冲区处理完,在这个套接字中没有新的事件再次到来时,在ET模式下是无法再次从epoll_wait调用中获取这个事件的。
而LT模式正好相反,只要一个事件对应的套接字缓冲区还有数据,就总能从epoll_wait中获取这个事件。
因此,LT模式下开发基于epoll的应用要简单些,不太容易出错。
而在ET模式下事件发生时,如果没有彻底地将缓冲区数据处理完,则会导致缓冲区中的用户请求得不到响应。
图示说明:
Nginx默认采用ET模式来使用epoll。
4.epoll的优点:
4.1.支持一个进程打开大数目的socket描述符(FD)
select
最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是2048。
对于那些需要支持的上万连接数目的IM服务器来说显然太少了。
这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的
Apache方案),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也不是一种完美的方案。
不过
epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat/proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。
4.2.2.IO效率不随FD数目增加而线性下降
传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合,不过由于网络延时,任一时间只有部分的socket是"
活跃"
的,但是select/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降。
但是epoll不存在这个问题,它只会对"
的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。
那么,只有"
的socket才会主动的去调用
callback函数,其他idle状态socket则不会,在这点上,epoll实现了一个"
伪"
AIO,因为这时候推动力在os内核。
在一些
benchmark中,如果所有的socket基本上都是活跃的---比如一个高速LAN环境,epoll并不比select/poll有什么效率,相反,如果过多使用epoll_ctl,效率相比还有稍微的下降。
但是一旦使用idleconnections模拟WAN环境,epoll的效率就远在s
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux epoll