您的位置:首页 > 其它

I/O 多路复用之 Select & Epoll

2016-03-07 11:03 281 查看
本文将简要介绍 select 、epoll 接口,并从接口的设计、调用方式分析两者的差异,最后总结两者功能的差异。当然,为什么么会有这些差异还得去研究相关接口的内核实现细节。

1. Select

[code]int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);


select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述副就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回。当select函数返回后,可以 通过遍历fdset,来找到就绪的描述符。

select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。select的一 个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但 是这样也会造成效率的降低。

2. Epoll

epoll 使用起来也很清晰,

首先调用
epoll_create
建立一个epoll 对象,返回文件 fd

epoll_ctl
可以操作上面建立的 epoll 对象进行,增添需要被监听新建立的 socket ,或从监听列表中删除某个 socket

epoll_wait
函数传递一个
struct epoll_event
结构参数,当在监控的所有句柄中有事件发生时,就返回数据已经准备就绪的 socket 文件描述符的数量

利用返回得到的准备就绪socket 的
num
(数量)轮询上面得到的
struct epoll_event
, 根据描述符的类型和事件类型分别进行处理

从上面的调用方式就可以看到epoll比select/poll的优越之处:epoll 只对活跃的 socket 进行事件处理,并且通过 add、delete 的方式来增减 socket,省去了不必要的重复拷贝。

3. Different

从 select 的调用方式就可以看出,每次调用都要传递需要监控的所有 FD_SET ,这意味着需要将用户态的描述符集 copy 到内核。而且 select 只是在有事件发生时才被唤醒,并没有给出哪些文件描述符是准备就绪的,必须得通过一次 O(n) 的线性扫描。

所以 select 有如下几点缺陷:

每次调用 select 都需要把fd集合从用户态拷贝到内核态

拷贝结束后 select 都需要在内核遍历传递进来的所有fd

select支持的文件描述符数量太小了,默认是1024

epoll 能解决上面三点缺陷

省去不必要的重复拷贝:epoll 通过内核与用户空间mmap同一块内存,保证了每个fd在整个过程中只会拷贝一次

效率:epoll 只会对”活跃”的socket进行操作—这是因为在内核中 epoll 是根据每个fd上面的 callback 函数实现的。只有”活跃”的socket才会主动的去调用 callback函数,其他idle状态socket则不会

epoll 没有最大文件符限制,它所支持的FD上限是最大可以打开文件的数目

4. Reference

Linux IO模式及 select、poll、epoll详解

IO多路复用之epoll总结

epoll 详解
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: