《linux》之IO教程
来源:
======================================================================================================
=============================================================================================================================================================================================================================================================================================================================================
============================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
int select(int maxfdp, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
简单理解select模型
理解select模型的关键在于理解fd\_set,为说明方便,取fd\_set长度为1字节,fd\_set中的每一bit可以对应一个文件描述符fd。则1字节长的
fd\_set最大可以对应8个fd,fd\_set是一个bitmap;
(1)执行fd\_set set; FD\_ZERO(&set) ,则set用位表示是0000,0000。
(2)若fd=5,执行FD\_SET(fd,&set) ,后set变为0001,0000(第5位置为1),若再加入fd=2,fd=1,则set变为0001,0011
(4)执行select(6, &set, 0, 0, 0),阻塞等待
(5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。
所以,我们可以得到select模型的特点:
(1) 文件描述符个数有限,长度和系统内存有关。select使用位域的方式来传递关心的文件描述符,位域就有最大长度。
select使用位域的方式传回就绪的文件描述符,调用者需要循环遍历每一个位判断是否就绪,当文件描述符个数很多,但是空闲的文件描
述符大大多于就绪的文件描述符的时候,效率很低。
(2) 将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集中的fd,
开始 select前都要重新从array取得fd逐一加入(FD\_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个参数。
在select 返回后,array作为源数据和fd\_set进行FD\_ISSET判断
select返回后会把以前加入的但并无事件发生的fd清空
(3) 可见select模型必须在select前循环array(加fd,取maxfd),select返回后循环array(FD\_ISSET判断是否有时间发生)。
为啥慢?
需要把 fd\_set 集合从用户态拷贝到内核态
调用 select 函数时,需要在内核遍历传递进来的所有 fd\_set
通知事件到来给用户进程,需要把整个 bitmap 拷到用户空间,让用户空间去查询。
不知道是哪些文件描述符有数据可以读写,需要把所有的文件描述符都轮询一遍才能知道。