Linux | 三种I/O函数(select,poll和epoll)

在Linux下,实现IO复用的系统调用主要有 select,poll 和 epoll。

1. select

用途:在一段时间内,监听用户感兴趣的文件描述符上的可读、可写和异常等事件。

(1)函数原型:

int select(int nfds, struct fd_set *readfds, struct fd_set *writefds,

struct fd_set *execptfds, struct timeval * timeout);

其中,各参数含义:

  • nfds:监听的最大文件描述符值+1
  • readfds:可读事件对应的文件描述符集合
  • writefds:可写事件对应的文件描述符集合
  • exceptfds:异常事件对应的文件描述符集合
  • timeout:设置 select 函数的超时时间。

函数返回值: 返回就绪的文件描述符数。

应用程序在调用 select 函数时,通过 readfds,writefds,exceptfds 三个参数传入自己感兴趣的文件描述符。select 函数调用返回时,内核将修改它们来通知应用程序那些文件描述符已经就绪。fd_set 结构体只包含一个整形数组,数组每一位表示一个文件描述符。

(2)文件描述符就绪的条件

满足下列条件之一,套接字可读:

1)socket 接收缓冲区当中的数据字节数大于等于套接字接收缓冲区中设置的最小值(即低水位标记,对于 TCP UDP 来说默认值为 1);

2)socket 通信的对方关闭连接。此时对该操作单 socket 返回0;

3)该套接字是一个监听套接字,且已完成的连接数不为0;对于这样的套接字,accept 通常不会阻塞;

4)socket 上有未处理的错误。

满足下列条件之一,套接字可写:

1)socket 发送缓冲区中可用字节数大于或等于套接字发送缓冲区当中设置的最小值时,并且或者 socket 已经连接,或者 socket 不需要连接(UDP);

2)socket 的写操作被关闭;

3)socket 上使用非阻塞 connect 连接成功或者失败之后;

4)socket 上有未处理的错误。

2. poll

用途:与 select 相似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有文件描述符就绪。

函数原型: 

int poll(struct pollfd *fds, int nfds, int timeout); 

其中,各参数含义:

  • fds 是一个 pollfd 结构类型的数组,如下:
struct pollfd
{
int fd; // 用户关注的文件描述符
short events; // 用户关注的事件类型
short revents; // 由内核填充
}
  • nfds 参数指定被监听事件集合 fds 的大小
  • timrout 参数指定 poll 的超时值,单位为毫秒

3. epoll

epoll 是 Linux 特有的I/O复用函数

(1)epoll 系列系统调用的主要接口

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

此函数如果检测到事件,就将所有就绪事件从内核事件表中(由 epfd 中的参数指定)复制到它的第二个参数 events 指定的数组中,这个数组只输出 epoll_wait 检测出的就绪事件。所以,搜索就绪文件描述符的时间复杂度为 O(1)。

(2)LT 模式和 ET 模式

1)LT 模式:在数据到达后,无论程序有没有接收,还是接收了但没有接收完,下一轮 epoll_wait 仍然会提醒应用程序该描述符上有数据,直到数据被接收完;阻塞和非阻塞模式均可。(反复提醒

2)ET 模式:在数据到达后,无论程序有没有接收,还是接收了但没有接收完,都只提醒一次,下一轮不再提醒应用程序该描述符上有数据;只能为非阻塞模式。(提醒一次

 

问:ET 模式为什么只能是非阻塞?不能是阻塞吗?

答:在 ET 模式下,I/O函数只提醒一次,若是一次将数据读不完,则需要循环读。如果是阻塞模式,循环读时程序不知道数据有没有被读完,当程序读不到数据时,程序会阻塞;如果设置为非阻塞模式,没有数据可读时程序就返回,返回值为-1。

 

4. select 和 poll 存在的问题(不足)

(1)select、poll 每次循环调用时,都需要从用户空间拷贝所有的文件描述符和时间到内核空间;

(2)内核以轮询的方式检查描述符上是否有事件产生,时间复杂度为O(n);

(3)select、poll 返回后,需要遍历所有的文件描述符才能找到就绪的,时间复杂度为O(n)。

5. epoll 的优点(与elect、poll 相比)

(1)不需要每次拷贝数据到内核空间,直接在内核空间创建事件表,每个数据仅需传递一次;

(2)在每个描述符上注册回调函数,事件就绪后,执行回调函数将描述符添加到就绪队列O(1);

(3)只返回就绪的描述符,不需要遍历所有的描述符O(1)。

 

附:三种I/O复用函数的比较

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值