【IO多路复用】 select,poll,epoll方法

引入:

img

这个函数功能和下面讲的select很像

select

img

首先注意到select函数,可以发现有五个参数,从左往右分别是接受文件的最大文件描述符,读文件集合,写文件集合,异常文件描述符,超时时间,注意rset,再上方有一个FD_SET操作,这一步是干什么呢?首先rset具体类型是一个bitMap,什么是bitMap,个人理解为位图,如下图

img

这一步主要是把文件中是否拥有数据,是否需要被监听的这些信息储存在bitMap中(1代表有数据,0代表无数据),所以得到了这个重要的bitMap后,会将用户态的bitMap传到内核态的bitMap,在select函数中交给内核态来判断,是否需要读文件呢?

img

值得注意的是,select也一个阻塞函数,如果传过来的bitMap全是0的话,select函数会一直阻塞,直到有数据读取时。

当有数据的时候,select函数会将fd置位,即bitMap置1,然后读取完成后返回select(已置位),即执行到下一行。

img

然后会跑到下面这个for循环,通过FD_ISSET判断哪一个fd被置位,然后将它处理(put)

解释完了rset,再来看看max,加入我们前面的描述符集合,分别是1,3,5,7,9,那么我们将max + 1 就是 10,即bitMap的大小会变成10位,方便我们置位。

select的缺点:

①bitMap默认大小只有1024

②在FD_SET之前每次都得清零(FD_ZERO),那么意味着我们不能重用bitmqp

③在整体拷贝bitMap到内核态时是仍会有一定的开销的(比我们for循环一个一个判断要好得多)

④最后仍需要进行一次O(n)的遍历

poll

img

poll函数的改动都是围绕结构体展开的!poll函数也是阻塞的!

那我们必然来看看结构体的组成

struct pollfd{

int fd;

short events;

short revents;

}

第一个就是文件描述符,第二个是当前的事件(读?写?读写?),第三个是对events的回馈(相当于我们上面的bitMap),当执行poll的时候,会对revent置位,就和select上面的功能是一样的,判断是否有数据。

再看执行完了poll函数之后,会对原先有数据的置revent零,注意此时的fd和event都是原先的,是可以重用的!这就解决了刚才上面select的第二个缺点。

注意在select的bitMap是上限1024的,但是我们这一次是结构体数组,容量也增大了

poll缺点:

③在整体拷贝类似于bitMap到内核态时是仍会有一定的开销的(比我们for循环一个一个判断要好得多)(还是得靠revent来判断!)

④最后仍需要进行一次O(n)的遍历

epoll

img

可以看到顶部有一个epfd = epoll_create(0),我们在调用epoll_create时,内核除了帮我们在epoll文件系统里建了个file结点,在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket外,还会再建立一个rdllist双向链表,用于存储准备就绪的事件

然后在虚线上的for循环中,对epfd写入数据,看epoll_ctl函数的第二个参数,代表增加写入!该方法写入了文件描述符和事件(读?写?),但是可以看到和上面poll方法的差别,没有revent字段(即类似于bitMap的那个玩意)!

所有添加到epoll中的事件都会与设备(如网卡)驱动程序建立回调关系,也就是说相应事件的发生时会调用这里的回调方法。这个回调方法在内核中叫做ep_poll_callback,它会把这样的事件放到上面的rdllist双向链表中。

当epoll_wait调用时,仅仅观察这个rdllist双向链表里有没有数据即可。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。所以,epoll_wait非常高效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值