多路复用select和epoll的区别(转)
先说下本文框架,先是问题引出,然后概括两个机制的区别和联系,最后介绍每个接口的用法
一、问题引出 联系区别
问题的引出,当需要读两个以上的I/O的时候,如果使用阻塞式的I/O,那么可能长时间的阻塞在一个描述符上面,另外的描述符虽然有数据但是不能读出来,这样实时性不能满足要求,大概的解决方案有以下几种:
1.使用多进程或者多线程,但是这种方法会造成程序的复杂,而且对与进程与线程的创建维护也需要很多的开销。(Apache服务器是用的子进程的方式,优点可以隔离用户)
2.用一个进程,但是使用非阻塞的I/O读取数据,当一个I/O不可读的时候立刻返回,检查下一个是否可读,这种形式的循环为轮询(polling),这种方法比较浪费CPU时间,因为大多数时间是不可读,但是仍花费时间不断反复执行read系统调用。
3.异步I/O(asynchronous I/O),当一个描述符准备好的时候用一个信号告诉进程,但是由于信号个数有限,多个描述符时不适用。
4.一种较好的方式为I/O多路转接(I/O multiplexing)(貌似也翻译多路复用),先构造一张有关描述符的列表(epoll中为队列),然后调用一个函数,直到这些描述符中的一个准备好时才返回,返回时告诉进程哪些I/O就绪。select和epoll这两个机制都是多路I/O机制的解决方案,select为POSIX标准中的,而epoll为Linux所特有的。
区别(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支持管道,FIFO,套接字,POSIX消息队列,终端,设备等,但就是不支持普通文件!!!
二、接口
1)select
1. int select(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds, struct timeval *restrict tvptr);
struct timeval{
long tv_sec;
long tv_usec;
}
有三种情况:tvptr == NULL 永远等待;tvptr->tv_sec == 0 && tvptr->tv_usec == 0 完全不等待;不等于0的时候为等待的时间。select的三个指针都可以为空,这时候select提供了一种比sleep更精确的定时器。注意select的第一个参数maxfdp1并不是描述符的个数,而是最大的描述符加1,一是起限制作用,防止出错,二来可以给内核轮询的时候提供一个上届,提高效率。select返回-1表示出错,0表示超时,返回正值是所有的已经准备好的描述符个数(同一个描述符如果读和写都准备好,对结果影响是+2)。
2.int FD_ISSET(int fd, fd_set *fdset); fd在描述符集合中非0,否则返回0
3.int FD_CLR(int fd, fd_set *fd_set); int FD_SET(int fd, fd_set *fdset) ;int FD_ZERO(fd_set *fdset);
用一段linux 中man里的话“FD_ZERO() clears a set.FD_SET() and FD_CLR() respectively add and remove a given file descriptor from a set. FD_ISSET() tests to see if a file descriptor is part of the set; this is useful after select() returns.”这几个函数与描述符的0和1没关系,只是添加删除检测描述符是否在set中。
2)epoll
1.int epoll_create(int size);
创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。
2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll的事件注册函数,它不同与select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。第一个参数是epoll_create()的返回值,第二个参数表示动作,用三个宏来表示:
EPOLL_CTL_ADD:注册新的fd到epfd中;
EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
EPOLL_CTL_DEL:从epfd中删除一个fd;
第三个参数是需要监听的fd,第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下:
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
events可以是以下几个宏的集合:
EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
关于epoll工作模式ET,LT
LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表.
ET (edge-triggered)是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了,但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once)
3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)
等待事件的产生,类似于select()调用。参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。
三、参考:
转载于:https://www.cnblogs.com/chd-zhangbo/p/5730506.html
多路复用select和epoll的区别(转)相关推荐
- IO多路复用select,poll epoll以及区别
看这个一次读懂 Select.Poll.Epoll IO复用技术 文章来简单理解下,如果不是很明白的话,可以参考下面转的知乎上面白话文列子 作者:Leslie 链接:https://www.zhihu ...
- java nio原理 epoll_多路复用 Select Poll Epoll 的实现原理(BIO与NIO)
BIO blocking阻塞的意思,当我们在后端开发使用的时候,accetp 事件会阻塞主线程. 当accept事件执行的时候,客户的会和服务建立一个socket 连接.一般后端就会开启一个线程执行后 ...
- select 和epoll模型区别
1.select 和epoll模型区别 1.1.网络IO模型概述 通常来说,网络IO可以抽象成用户态和内核态之间的数据交换.一次网络数据读取操作(read),可以拆分成两个步骤:1)网卡驱动等待数据准 ...
- IO多路复用select/poll/epoll详解以及在Python中的应用
IO multiplexing(IO多路复用) IO多路复用,有些地方称之为event driven IO(事件驱动IO). 它的好处在于单个进程可以处理多个网络IO请求.select/epoll这两 ...
- socket 编程篇六之IPO多路复用-select poll epoll
http://blog.csdn.net/woxiaohahaa/article/details/51498951 文章参考自:http://blog.csdn.net/tennysonsky/art ...
- PostgreSQL中的io多路复用--select和epoll实现
某天和同事闲聊,同事发现一个现象,PostgreSQL在空闲状态时(没有active连接),主进程的pstack显示一直在调用/lib64/libc.so.6的__select_nocancel () ...
- python3 异步 非阻塞 IO多路复用 select poll epoll 使用
有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理还是有必要的. 下面记录下分别基于Select/Poll/Epoll的echo ser ...
- IO模型(select, poll, epoll的区别和原理)
参考<unix网络编程> 参考http://blog.csdn.net/blueboy2000/article/details/4485874 参考http://blog.csdn.net ...
- python poll_python IO 多路复用 select poll epoll
select select 原理 select 是通过系统调用来监视着一个由多个文件描述符(file descriptor)组成的数组,当select()返回后,数组中就绪的文件描述符会被内核修改标记 ...
最新文章
- 查找字符串里面有没有相同的字符- -
- python如何批量发布数据并如何定时更换token
- Asp.net MVC Action大全(转)
- 图解 MongoDB 地理位置索引的实现原理
- 案例-翻转的导航栏(CSS3)
- XILINX-DDR3IP核的使用
- JavaScript基础入门
- 动手了!限19天,大米云主机满10送2手慢无!
- 云存储收银系统_爱宝云收银系统
- 现代互联网的TCP拥塞控制(CC)算法评谈
- Qt实用技巧:自定义窗口标题栏
- 新手怎样才能快速的学会建网站
- C++初学者必练基础编程题【第一期】
- 自然保护区相关矢量数据下载
- 迅为I.MX6ULL开发板镜像烧写
- 如何建立自己的认知体系
- Bootstrap 信息提示框
- 金钱观与经济状况的一致性
- 股权激励如何选择持股人
- ROS18.04+ Gazebo9 + robotiq85 视觉机械臂抓取仿真