epoll

select poll epoll系统调用详细分析

 

epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

 

epoll的EPOLLLT模式和EPOLLET模式比较

http://blog.csdn.net/lcabcdefg/article/details/7243277

epoll是linux系统最新的处理多连接的高效率模型, 工作在两种方式下, EPOLLLT方式和EPOLLET方式。

EPOLLLT是系统默认, 工作在这种方式下, 程序员不易出问题, 在接收数据时,只要socket输入缓存有数据,

都能够获得EPOLLIN的持续通知, 同样在发送数据时, 只要发送缓存够用, 都会有持续不间断的EPOLLOUT

通知。而对于EPOLLET是另外一种触发方式, 比EPOLLLT要高效很多, 对程序员的要求也多些, 程序员必须

小心使用,因为工作在此种方式下时, 在接收数据时, 如果有数据只会通知一次, 假如read时未读完数据,

那么不会再有EPOLLIN的通知了, 直到下次有新的数据到达时为止; 当发送数据时, 如果发送缓存未满也只有

一次EPOLLOUT的通知, 除非你把发送缓存塞满了, 才会有第二次EPOLLOUT通知的机会, 所以在此方式下

read和write时都要处理好。 暂时写到这里, 留作备忘。

        附加: 如果将一个socket描述符添加到两个epoll中, 那么即使在EPOLLET模式下, 只要前一个epoll_wait时,未读完, 那么后一个epoll_wait事件时, 也会得到读的通知, 但前一个读完的情况下, 后一个epoll就不会得到读事件的通知了。。。。。

 

epoll和select区别

http://blog.csdn.net/ysu108/article/details/7570571

区别(epoll相对select优点)主要有三:

1.select的句柄数目受限,在linux/posix_types.h头文件有这样的声明:#define __FD_SETSIZE    1024  表示select最多同时监听1024个fd。而epoll没有,它的限制是最大的打开文件句柄数目。

2.epoll的最大好处是不会随着FD的数目增长而降低效率,在selec中采用轮询处理,其中的数据结构类似一个数组的数据结构,而epoll 是维护一个队列,直接看队列是不是空就可以了。epoll只会对"活跃"的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面 的callback函数实现的。那么,只有"活跃"的socket才会主动的去调用 callback函数(把这个句柄加入队列),其他idle状态句柄则不会,在这点上,epoll实现了一个"伪"AIO。但是如果绝大部分的I/O都是 “活跃的”,每个I/O端口使用率很高的话,epoll效率不一定比select高(可能是要维护队列复杂)

3.使用mmap加速内核与用户空间的消息传递。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。

注:第三点貌似有问题. epoll的内核实现中并没有使用到mmap. 示例如下:

在epoll_ctl中,有:

1141 /*                                                                                                        
1142  * The following function implements the controller interface for                                         
1143  * the eventpoll file that enables the insertion/removal/change of                                        
1144  * file descriptors inside the interest set.                                                              
1145  */                                                                                                       
1146 SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,                                                   
1147         struct epoll_event __user *, event)                                                               
1148 {                                                                                                         
1149     int error;                                                                                            
1150     struct file *file, *tfile;                                                                            
1151     struct eventpoll *ep;                                                                                 
1152     struct epitem *epi;                                                                                   
1153     struct epoll_event epds;                                                                              
1154                                                                                                           
1155     DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n",                             
1156              current, epfd, op, fd, event));                                                              
1157                                                                                                           
1158     error = -EFAULT;                                                                                      
1159     if (ep_op_has_event(op) &&                                                                            
1160         copy_from_user(&epds, event, sizeof(struct epoll_event)))                                         
1161         goto error_return;   

 

在epoll_wait中,最终会调到此函数:

 945         /*
 946          * Is the event mask intersect the caller-requested one,
 947          * deliver the event to userspace. Again, we are holding                                          
 948          * "mtx", so no operations coming from userspace can change                                       
 949          * the item.
 950          */
 951         if (revents) {
 952             if (__put_user(revents,
 953                        &events[eventcnt].events) ||
 954                 __put_user(epi->event.data,
 955                        &events[eventcnt].data))                                                           
 956                 goto errxit;
 957             if (epi->event.events & EPOLLONESHOT)
 958                 epi->event.events &= EP_PRIVATE_BITS;
 959             eventcnt++;
 960         }

其中put_user --  Write a simple value into user space. This function may sleep.

 

copy_to_user,copy_from_user,get_user,put_user函数比较

 注:epoll_create中的参数没有什么用

 1133 SYSCALL_DEFINE1(epoll_create, int, size)                                                                  
1134 {                                                                                                         
1135     if (size <= 0)                                                                                        
1136         return -EINVAL;                                                                                   
1137                                                                                                           
1138     return sys_epoll_create1(0);                                                                          
1139 }  

 

 

 EPOLL的内核实现

 epoll的内核实现

1. select/poll的缺点

     A. 每次调用时重复的从用户态读入参数

     B. 每次调用时全量的扫描文件描述符

     C. 每次调用开始,将进程加入到每个文件描述符的等待队列,在调用结束后又把进程从等待队列中删除。

     D. 在不修改内核的情况下,select最多支持1024个文件描述符。

 

epoll完整实例

http://www.cppblog.com/API/archive/2013/07/01/201424.html

求教:epoll的ET模式对EPOLLOUT事件怎么处理的?

有关epoll的EPOLLOUT

三种使用场景:

  1: 对客户端socket只使用EPOLLIN(读)监听,不监听EPOLLOUT(写),写操作一般使用socket的send操作

  2:客户端的socket初始化为EPOLLIN(读)监听,有数据需要发送时,对客户端的socket修改为EPOLLOUT(写)操作,这时EPOLL机制会回调发送数据的函数,发送完数据之后,再将客户端的socket修改为EPOLL(读)监听

 3:对客户端socket使用EPOLLIN 和 EPOLLOUT两种操作,这样每一轮epoll_wait循环都会回调读,写函数,这种方式效率不是很好

posted @ 2013-11-18 16:44  静之深  阅读(480)  评论(0编辑  收藏  举报