epoll学习(一)
来源:互联网 发布:网店美工毕业论文 编辑:程序博客网 时间:2024/05/18 00:42
Epoll是当前Linux下开发大规模并发程序设计的热门选择,Epoll在Linux2.6内核引入,和select相似,其实都是I/O多路复用技术。
select , poll 模型:
1:最大并发数限制,因为一个进程打开文件描述符是有限制的,由FD_SETSIZE限制。
2:效率问题,select每次调用都会线性扫描全部的文件描述符集合,这样效率就会线性下降。
3:内核/用户空间内存拷贝问题,select采用内存拷贝方法。
Epoll :
1:epoll支持的文件描述符上限是最大可以打开文件数目,这个数字远大于2048,具体数目可到cat /proc/sys/fs/file-max查看。
2:效率提升,Epoll最大的优点它只管活跃的连接,而跟连接总数无关,,因此在实际网络,Epoll效率远高于select和poll。
3:使用mmap加速内核与用户空间的消息传递,通过内核与用户空间映射同一块内存实现。
select每次调用时都要传递你所要监控所有socket给select系统调用,这意味着将用户态socket列表cpoy到内核态,如果很多句柄会导致每次都要copy几十或几百kb内存到内核,非常低效,而我们调用epoll时就相当于以往调用select/poll,但这时并不传递socket句柄给内核,因为内核已经在epoll_ctl()拿到了要监控的列表。所以在调用epoll_create后内存已经帮你储存要监控的描述符,每次调用epoll_ctl只是往数据结构添加新的描述符,调用epoll_wait收集发生事件的连接。
epoll相关系统调用:
epoll只有epoll_create,epoll_ctl,epoll_wait三个系统调用。
1. int epoll_create (int size) ; epoll返回一个句柄,之后的epoll使用都将依靠这个句柄标识,参数size是告诉epoll所要处理大致事件数目,不再使用时,要close(),在Linux最新的内核版本size无任何意义。
2. int epoll_ctl (int epfd , int op , int fd , struct epoll_event *event) ; 向epoll对象添加、修改或删除事件,成功返回0,失败返回-1,第一个参数是epoll_create()返回值,第二个参数表示动作,由三个宏表示:
EPOLL_CTL_ADD: 注册新的fd事件到epoll中。
EPOLL_CTL_MOD:修改已经注册的epoll事件。
EPOLL_CTL_DEL:从epfd删除一个fd。
第三个参数是需要监听连接套接字。第四个参数是告诉epoll对什么样的事件监听,它使用了struct epoll_event。
struct epoll_event {
__uint32_t events ; //监听事件类型
epoll_data_t data ; //epoll_data集合
} ;
typedef union epoll_data {
void *ptr ;
int fd ;
uint32_t u32 ;
uint64_t u64 ;
} epoll_data_t ;
events可以是以下几个宏组合:
EPOLLIN:表示对应的文件描述符可读。
EPOLLOUT:表示对应的文件描述符可写。
EPOLLPRI:表示对应的文件描述符有紧急数据可读。
EPOLLHUP:表示对应的文件描述符挂断。
EPOLLET:将触发方式设置为边缘出发(ET),默认为水平触发(LT)。
EPOLLNESHOT:表示这个事件只处理一次,下次重新处理时需重新加入epoll。
int epoll_wait(int epfd , struct epoll_event *events , int maxevents , int timeout)
收集在epoll监控的事件已经发生的事件,如果epoll中没有任何一个事件发生,则最多等待timeout毫秒后返回,返回值表示当前发生事件个数,出错返回-1,第二个参数events是已经分配好空间的epoll_event结构体数组,epoll会把已经发生事件复制到events数组(events不可以是空指针,内核负责把事件相关信息复制到events数组,不会去帮助我们在用户态中分配内存)maxevents表示本次可以返回的最大事件数目,每次能处理的事件数,通常与预分配events数组大小相等,不能大于epoll_create()时的size。
epoll工作:epoll只通知那些就绪的FD,当调用epoll_wait()获得这些就绪FD,返回一个就绪描述符数量的值,用户只需去epoll指定的一个events数组获取相应位置的描述符,使用了内存映射mmap方法,节省系统调用开销。另外改进是epoll采用基于事件通知的就绪通知方式,当某个文件描述符就绪时,内核就会采用callback回调机制,当进程调用epoll_wait()就会得到通知。
epoll有两种工作模式,LT(水平模式)和ET(边缘模式)。假如有这样一个例子:
1.我们已经把一个用来读取数据的FD添加到epoll描述符
2.这时候管道从另一段写入2KB数据
3.调用epoll_wait(),并且他会返回FD,说明他已经准备好读数据
4.然后读取1K数据
5.调用epoll_wait()。。。。。。。
边缘工作模式(ET):
如果我们第一步把FD添加到epoll描述符的时候使用EPOLLET标志,那么在最后调用epoll_wait()后将有可能挂起,因为剩余的数据还存在于文件的输入缓冲区中,而且数据发出端还在等待一个针对已发出数据的反馈信息,只有在监视文件FD发生某个事件的时候ET工作模式才会报告此事件。因为在第5步,调用者可能会放弃等待仍存在于数据缓冲区的剩余数据。在上面例子中,会有一个事件产生在文件FD上,因为第2步执行写操作,然后事件将在第3步摧毁,因为第4步的读取操作没有读空文件缓冲区数据,因此在第5步调用epoll_wait()后是否不一定挂起,epoll工作在ET模式,必须使用非阻塞套接口,以避免由于一个文件描述符的阻塞读/写操作把多个描述符操作饿死,最好以下面方式调用ET模式的epoll接口 1:基于非阻塞的文件描述符 2:只有当read()或write()返回EAGAIN才需要挂起,等待。但这并不是说每次read()都需要循环读,直到读到产生一个EAGAIN才认为此事件处理完成,当read()返回读到数据长度小于请求数据长度时,就可以确定此缓冲区没有数据,此事件已经处理完成。
水平工作模式(LT):
缺省工作模式,并且同时支持block和non-block状态,内核会告诉你一个文件描述符是否就绪,然后对就绪的fd进行IO操作,如果不做任何操作,内核还会通知,所以这种模式出错可能性较小。
ET模式的效率要比LT模式效率要高,它只支持非阻塞套接字。ET模式和LT模式区别在于,当一个新的时间到来时,ET模式当然可以从epoll_wait()获取到该事件,可是如果这次没有把这事件对应套接字缓冲区处理完,在这个套接字没有新的事件到来时,ET模式无法从epoll_wait调用中获取事件,而LT相反,只要一个事件对应套接字缓冲区还有数据,就能从epoll_wait获取这个事件。因此,在LT模式下开发epoll应用简单,而在ET模式下事件发生时,如果没有彻底将缓冲区数据处理完,而会导致缓冲区内的用户请求得不到响应,默认情况,Nginx通过ET使用epoll。
- epoll学习(一)
- epoll简介(一)
- epoll学习(二)
- EPOLL技术总结(一)
- epoll模型使用(一)
- 一个epoll例子(一)
- epoll 学习
- epoll学习
- EPOLL学习
- epoll()学习
- 学习epoll
- epoll学习
- epoll学习
- epoll学习
- epoll学习
- EPOLL学习
- epoll详解-epoll学习笔记
- epoll源码学习笔记(linux2.6.32)
- Struts2中action跳转jsp页面CSS失效的问题分析
- 面向对象的控制驱动部分--总结
- 人机交互学习总结--OOAD
- Emacs学习手记
- debian7.5
- epoll学习(一)
- 设计模式-----观察者模式(Obsever)
- 类图学习总结-OOAD
- Qt 信号槽的实现
- 用 emacs org-mode 写日志
- epoll学习(二)
- 反转字符串的单词
- 用况图学习总结--OOAD
- 用Org-mode实践《奇特的一生》