select、poll、epoll详解

转载请注明出处:http://blog.csdn.net/windeal3203

一、IO多路复用

  网络通信中,select、poll、epoll主要用于提供IO多路复用的解决方案。
 IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合:

  • (1) 当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。
  • (2) 当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。
  • (3) 如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。
  • (4) 如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。
  • (5) 如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。

     与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

二、几种常用的I/O复用模型

1 select

编程接口

select的编程接口如下,

#include <sys/select.h>
#include <sys/time.h>

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

返回值:就绪描述符的数目,超时返回0,出错返回-1

select模型仅有一个函数select(),
nfds: 要监听的文件描述符的范围, 通常使用select监听的所有描述符的最大值加1。
readfds: 要监听是否有可读事件的文件描述符集
writefds:要监听是否有可写事件的文件描述符集
exceptfds:要监听是否有异常事件的文件描述符集
timeout: 阻塞时间

实现原理

理解select I/O复用模型的关键点在于 fd_set,这是一个整形数组,数组的每个成员的每一位都表示一个文件描述符。
在调用select的时候,用户空间将要检测的各种事件的文件描述符以fd_set 整型数组的形式传递给内核空间。
内核空间通过轮询监听的描述符集判断是否有监听事件发生。如果某个描述符上有对应的监听事件发生,则该描述符对应的位置1, 跳出阻塞,执行select函数之后的代码; 否则,select继续阻塞,CPU资源让出给其他进程。

不足

  1. select模型中,向内核传递监听的描述符集合轮询检测监听事件都使用一个函数select实现,每一次执行select函数都要重新向内核空间传递表示监听描述符集的整型数组。其实这是不必要的,因为在一个服务器中,其要监听的描述符集一般是相对稳定的,很少变化。因而,只需要向内核空间传递一次描述符集就可以了。
  2. select模型使用整型数组来描述要监听的描述符集,因为它能监听的描述符的个数是有限的。
  3. select模型在检测是否有时间发生时,需要遍历轮询所有的监听描述符,这需要花费一定的开销。

以上两点不足,可以在epoll得到一定程度的改善

pselect

2 poll

编程接口

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

实现原理

poll模型在实现原理上和select模型差不多,只是在对监听描述符集的描述上有所差异。
poll模型使用struct pollfd结构体描述要监听的描述符集。

从性能或者是系统开销上看,poll和select的差别不大,目前使用select模型的服务器较多,相比之下poll的使用并不广泛。

3 epoll

编程接口

与select、poll模型都只使用一个函数不同,epoll模型用到了一组(三个)函数来实现I/O复用:

#include <sys/epoll.h>
int epoll_create(int size); //
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

这组函数的作用如下:
epoll_create用于创建一个额外的文件描述符,该描述符用语标识服务器要监听的事件在内核中对应的事件表。
epoll_ctl 用于操作参数epfd(由之前的epoll_create函数生成)对应的内核事件表,如向事件表中注册、修改、删除事件。
epoll_wait是epoll模型的主要函数,它用于(在超时时间timeout内)阻塞监听是否有我们关注(注册)的事件发生。

实现原理

首先,用户空间通过epoll_ctl函数讲要监听的的各个描述符的事件传递给内核空间。另外,epoll_ctl会为每个描述符指定回调函数,当该描述符上有事件发生时,会调用回调函数,将文件描述符添加到一个就绪队列中去。

epoll_wait用于阻塞监听各个文件描述符是否有监听的事件发生,因为在epoll_ctl中我们为每个要监听的描述符指定了回调函数,因此epoll_wait不需要轮询检测各个文件描述符了,只需要判断就绪队列是否为空即可。

三、几种模型的对比

poll和select的区别主要是在对监听描述符的表示上,其实现原理和性能区别不大,这里我们主要对比select模型和epoll模型的不同。
epoll对select模型的几点不足做出了改进。
1. select每次调用select都需要重新想内核传递监听的描述符,浪费了一些开销。 而epoll模型对每个描述符只需要利用epoll_ctl做一次处理,之后epoll_wait阻塞监听时不再需要向内核空间传递要监听哪一些描述符
2. epoll模型并非向select模型那样使用整型数组来表示监听的描述符集,因而能够监听的文件描述符较大
3. select模型在阻塞监听时需要轮询每个监听的文件描述符,而epoll只需要判断就绪队列是否为空。相比之下,在没有监听的事件发生时,epoll能更早地让出系统资源,让CPU调度运行其他进程。

四、I/O复用模型的应用场景

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值