三者都是UNIX下多路复用的内核接口,select是跨平台的接口,poll是systemV标准,epoll是linux专有的接口,基于poll改造而成。

select

函数原型:

int select (int n,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout);
  select通过系统调用监视多个文件描述符的数组,select返回后,就绪的文件描述符会被修改标志位,使得进程可以获得准备就绪的文件描述符并继续I/O操作。

select目前的优点就是几乎所有的系统都支持select,缺点是最大只能监听1024个文件描述符,想监听超过1024个文件描述符时需要手动修改FD_SETSIZE大小,但这样活造成网络I/O性能下降;或者创建多进程,每个进程监听1024个文件描述符,这样会导致程序复杂度增加。

select的第一个参数n需要程序员自己处理,n为所有集合中最大的文件描述符值+1;select的第二个参数readfds列举的文件描述符被监视是否有可供读取的数据;select的第三个参数writefds列举的文件描述符被监视是否写入完成而不阻塞;select的第三个参数exceptfds列举的文件描述符被监视是否异常或者无法控制的数据是否可用(这些状态仅用于套接字);当文件描述符列表设置为NULL时该类文件描述符不被监视。select的第四个参数timeout用于设置超时时长,当select经过了timeout时长后仍然没有可用的文件描述符也将返回;select的返回值代表了当前可用的文件描述符的数量,范围为0-1024,当超时返回时返回值为0,其他时候是1-1024区间的值。

struct timeval {

long tv_sec; /* seconds */
long tv_usec; /* 10E-6 second */

};

如果select的timeout参数不为NULL,即便没有文件描述符准备好I/O,也会在等待ty_sec秒和ty_usec微秒后select返回,timeout在不同系统中的处理是不同的,最好每次调用select前设置一次。

向select监视的文件描述符集合中添加或者删除文件描述符通常采用系统定义的宏进行

FD_ZERO:将集合清空

FD_SET:向集合中添加一个文件描述符

FD_CLR:从集合中删除一个文件描述符

FD_ISSET :指定的文件描述符是否在集合中

能够放进fd_set中的最大的文件描述符值是1024,这个值是由FD_SETSIZE决定的。

select调用成功后非NULL的文件描述符集合将被修改,集合中将只剩下准备好的文件描述符,通过FD_ISSET轮询所有集合确定准备好I/O的文件描述符。

select的缺点:在于维护的存储文件描述符的数据结构需要在内核空间和用户空间来回复制,随着文件描述符数量的增加,复制所花费的开销也线性增长; 由于网络延迟,很多socket会处于非活跃状态,但select也会对其进行一次扫描。这两个缺点导致select的效率随文件描述符数量降低,在处理大量fd非活跃的集合时效率降低。

select仅支持水平触发(Level Triggered):即一个fd被返回可用后,如果没有对该fd进行I/O操作,那么下次select返回时仍然报告该fdI/O可用。

poll

poll和select本质上类似,但不存在最大文件描述符数量的限制,poll和select存在一样的缺点:维护的文件描述符数据结构在内核空间和用户空间来回拷贝,效率随监视的文件描述符数量而下降。

int poll (struct pollfd *fds, unsigned int nfds, int timeout);
  struct pollfd {
int fd; /* file descriptor */
short events; /* requested events to watch */
short revents; /* returned events witnessed */
};

poll中的每一个pollfd指明一个被监视的文件描述符,nfds指明最大监视的文件描述符数,timeout代表了超时时长,单位为毫秒。

pollfd结构体的fd是文件描述符;events是要监视的事件掩码;revents是被监视的文件描述符操作结果事件掩码,内核在返回时设置这个域。每一个events都可能在revents中被返回。

epoll

epoll是linux2.6以后出现的内核直接支持的方法,具有了select和poll的一切优点,被认为是linux2.6下最优秀的I/O就绪通知方式。

epoll可以支持水平触发(Level Triggered)和边缘触发(Edge Triggered,当文件描述符就绪时仅通知进程一次,即使进程没有对其进行I/O操作,以后也不会再通知),边缘触发方式适合高速I/O,但编程实现较为复杂。

epoll同样只告知那些准备就绪的文件描述符,当调用epoll_wait成功返回时,返回值代表准备就绪的文件描述符,此时epoll一个指定的数组中取出相应数量的文件描述符即可,epoll采用了文件映射技术(mmap),内核和用户态访问同一段内存,避免了文件描述符在内核和用户态之间的互相复制;epoll还采用了基于事件的就绪通知方式,epoll事先通过epoll_ctl注册一个文件描述符,一旦某个文件描述符就绪时,系统会采用类似于callback的机制迅速激活这个文件描述符,当进程调用epoll_wait便得到通知。

epoll的优点有可监视的文件描述符数量等于系统可打开的最大文件描述符;epoll的效率不随监视的文件描述符数量增加而线性下降;epoll通过文件映射减少了内核和用户态数据复制开销。

函数原型

int epoll_create(int size);

创建一个epoll句柄,指定要监听的文件描述符数量

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

对epoll句柄进行操作

epfd指定epoll句柄;

op为指定的操作EP_CTL_ADD(注册新的句柄到epoll);EP_CTL_MOD(修改已经注册的文件描述符的监听事件);EP_CTL_DEL(删除一个已经注册的fd)

fd为要注册的文件描述符

event为监听的事件

epoll_event结构如下:

struct epoll_event {

__uint32_t events; /*Epoll events*/

epoll_data_t data; /*User data variable*/

}

events可以用以下几个宏的集合

EPOLLIN:当前文件描述符可读

EPOLLOUT:当前文件描述符可以写

EPOLLPRI:当前文件描述符有紧急数据可以读(应该表示有带外数据到来)

EPOLLERR:当前文件描述符发生错误

EPOLLHUP:对应的文件描述符被挂断

EPOLLET:将EPOLL设置为边缘触发模式

EPOLLONESHOT:只监听一次事件,当完成一次监听以后还需要监听该描述符的话需要再次加入到EPOLL队列中。

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

等待事件的发生,类似select返回。

后记

本次学习笔记基于网络搜索,非原创,也没有用到select、poll、epoll,可以说从零开始学,难免有些浅薄,待以后有了实际经验会进行补充。

补充

IPC和select、poll、epoll能否同时使用?通常不可以,这会带来不少麻烦,因为IPC的实现方式并不是文件描述符,如果需要同时使用IPC和多路复用(select、poll、epoll),可以采用fork子进程,然后父进程和子进程采用IPC或管道通信,其中一个进程使用多路复用技术监控文件描述符。

多路复用技能着重处理的文件描述符是socket、管道、伪终端(pty)、终端设备(tty)等系统文件描述符,对普通文件描述符不起作用。

【UNIX】select、poll、epoll学习的更多相关文章

  1. Java IO 学习(二)select/poll/epoll

    如上文所说,select/poll/epoll本质上都是同步阻塞的,但是由于实现了IO多路复用,在处理聊天室这种需要处理大量长连接但是每个连接上数据事件较少的场景时,相比最原始的为每个连接新开一个线程 ...

  2. 哪5种IO模型?什么是select/poll/epoll?同步异步阻塞非阻塞有啥区别?全在这讲明白了!

    系统中有哪5种IO模型?什么是 select/poll/epoll?同步异步阻塞非阻塞有啥区别? 本文地址http://yangjianyong.cn/?p=84转载无需经过作者本人授权 先解开第一个 ...

  3. select/poll/epoll on serial port

    In this article, I will use three asynchronous conferencing--select, poll and epoll on serial port t ...

  4. Python之路-python(Queue队列、进程、Gevent协程、Select\Poll\Epoll异步IO与事件驱动)

    一.进程: 1.语法 2.进程间通讯 3.进程池 二.Gevent协程 三.Select\Poll\Epoll异步IO与事件驱动 一.进程: 1.语法 简单的启动线程语法 def run(name): ...

  5. 多进程、协程、事件驱动及select poll epoll

    目录 -多线程使用场景 -多进程 --简单的一个多进程例子 --进程间数据的交互实现方法 ---通过Queues和Pipe可以实现进程间数据的传递,但是不能实现数据的共享 ---Queues ---P ...

  6. Python自动化 【第十篇】:Python进阶-多进程/协程/事件驱动与Select\Poll\Epoll异步IO

    本节内容: 多进程 协程 事件驱动与Select\Poll\Epoll异步IO   1.  多进程 启动多个进程 进程中启进程 父进程与子进程 进程间通信 不同进程间内存是不共享的,要想实现两个进程间 ...

  7. select poll epoll三者之间的比较

    一.概述 说到Linux下的IO复用,系统提供了三个系统调用,分别是select poll epoll.那么这三者之间有什么不同呢,什么时候使用三个之间的其中一个呢? 下面,我将从系统调用原型来分析其 ...

  8. 转--select/poll/epoll到底是什么一回事

    面试题:说说select/poll/epoll的区别. 这是面试后台开发时的高频面试题,属于网络编程和IO那一块的知识.Android里面的Handler消息处理机制的底层实现就用到了epoll. 为 ...

  9. IO多路复用select/poll/epoll详解以及在Python中的应用

    IO multiplexing(IO多路复用) IO多路复用,有些地方称之为event driven IO(事件驱动IO). 它的好处在于单个进程可以处理多个网络IO请求.select/epoll这两 ...

  10. [serial]基于select/poll/epoll的串口操作

    转自:http://www.cnblogs.com/darryo/p/selectpollepoll-on-serial-port.html In this article, I will use t ...

随机推荐

  1. 115. Distinct Subsequences

    题目: Given a string S and a string T, count the number of distinct subsequences of T in S. A subseque ...

  2. 基于web的项目管理软件Redmine

    Redmine是用Ruby开发的基于web的项目管理软件,是用ROR框架开发的一套跨平台项目管理系统,据说是源于Basecamp的ror版而来, 支持多种数据库,有不少自己独特的功能,例如提供wiki ...

  3. 【HDOJ】4326 Game

    1. 题目描述一个长度为n个队列,每次取队头的4个人玩儿游戏,每个人等概率赢得比赛.胜者任然处在队头,然而败者按照原顺序依次排在队尾.连续赢得m场比赛的玩家赢得最终胜利.求第k个人赢得最终胜利的概率. ...

  4. 【HDOJ】2890 Longest Repeated subsequence

    后缀数组的应用.和男人八题那个后缀数组差不多. /* 2890 */ #include <iostream> #include <sstream> #include <s ...

  5. OAF与Windows 7版本不兼容黑屏卡顿问题

    OAF版本比较原始,在Window7中无法应用配色方案,导致黑屏卡顿问题.(在启动OC4J后,Window7的配色方案还是会还原至原始状态) 修改$JDEV_HOME/jdev/bin/jdev.co ...

  6. Android使用Webview加载网页

    安卓使用Webview来加载和显示网页内容,首先在layout文件中定义Webview <?xml version="1.0" encoding="utf-8&qu ...

  7. C++学习笔记:List容器

    http://www.cplusplus.com/reference/list/list/ #include <list> list l:初始化一个0大小的表 list l(10):初始化 ...

  8. android ListView注意事项

    所有问题,都是自己遇到过的. 但内容,有一半是自己写的,也有一半是复制过来. 所以,写成原创还请原谅 1. ListView添加标题后(addHeader())后,使用listView.getAdap ...

  9. C#多线程下载一个文件

    这里只是说明多线程下载的理论基础,嘿嘿,并没有写多线程下载的代码,标题党了,但是我相信,看完这个代码就应该能够多线程的方式去下载一个文件了. 多线程下载是需要服务器支持的,这里并没有判断服务器不支持的 ...

  10. 明修栈道,暗渡陈仓----之私募一哥徐翔新玩法 z

    前言:去年以来,因徐翔和宁电突然举牌资质平平的 000692 惠天热电,引起本人的兴趣,陆陆续续花了比较多的时间和精力去研究和跟踪000692惠天热电,期间也两次亲自去沈阳调研,从一些台前幕后人士那里 ...