I/O多路复用之select

        系统提供select函数用来实现I/O多路复用输入/输出模型。selsect系统调用是用来让我们的程序监视多个文件描述状态变化的。程序会停在select这里等待,直到被监视文件描述符有一个或多个发生状态变化。通常I/O操作有两个步骤,一个是等,另一个是数据搬迁。select主要是在等的这个状态阻塞着直到事件发生。

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

函数原型

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

参数:
nfds:需要监视的最大的文件描述符的值+1.

fd_set:底层通过位图实现,每一个位都代表一个文件描述符。readfds,writefds,exceptfds分别对应于需要检测的可读文件描述符结合,可写描述符集合,异常文件描述符集合,他们都属于输入输出型参数。

当作为输入参数时:只要文件描述符集合中对应的位上为1,就表示select需要监视这个描述符的状态。比如readfds里面的文件描述符就表示他们需要等待读事件,writefds里面的文件描述符就代表他们需要等待事件。

当作为输出参数时:只要文件描述符集合中对应位为1,就代表他们等待的事件已经就绪,这是由内核设定的。

timeout:设置超时时间

timeout里面的成员设定为特定的时间值:
如果在这段时间里面没有事件发生,select将超时返回。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监听的描述符没有事件发生则函数返回,返回值为0.

struct timeval
{
    long tv_sec;        //秒
    long tv_usec;        //微秒
}
timeout里面的成员等于0:表示非阻塞轮询方式,不断的去检测描述符集合的状态,然后立即返回。
timeout为NULL:表示以阻塞的方式等待事件发生。

返回值:
成功的话,返回文件描述符状态已改变的个数。如果返回0代表在描述符状态改变之前已经超过timeout事件。如果有错误发生的话,则返回-1。

下面的宏用来处理描述符集合:
void FD(int fd, fd_set* set);    // 用来清除描述符词组set中相关fd的位。
int FD_ISSET(int fd, fd_set* set);    // 用来测试set中相关fd的位是否为真。
void FD_SET(int fd, fd_set* set);    // 用来设置描述词组set中相关fd的位。
void FD_ZERO(fd_set* set);    // 用来清除描述词组set的全部位。



Select模型

        select可监控的描述符取决于sizeof(fd_set)的值,因为文件描述符是用位图表示的,所以能监控的描述符的最大数量是sizeof(fd_set)* 8, fd_set的大小可以调整。

        将fd加入select监控集的同时,还要使用一个额外的数组保存select监控集中的fd。一方面是用于在select返回后,array作为源数据和fd_set进行FD_ISSET判断事件是否就绪。另一方面是select返回之后会把以前加入的但无事件发生fd清空,这是由内核清空的,所以每次开始select前都要重新从array中取得fd加入到fd_set中。

        还有就是因为select第一个参数是当前要监测的文件描述符的最大值加1,可以在扫描array的同时取得fd的最大值maxfd,用于select的第一个参数。

        所以select的缺点就是,每次select之前都要遍历数组加入fd,select返回后还要遍历数组进行判断哪些事件已经就绪(FD_ISSET判断是否有事件发生)。

select的缺点

1.每次调用select,都需要把fd集合从用户态拷贝到内核态。这个开销在fd很多的时候会很大。

2.select在返回之后,需要我们遍历数组去查找事件就绪的描述符。这个过程的时间复杂度O(N)。而epoll它查找就绪事件的时候是O(1)。

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

总结:针对select的缺点来看,即时fd_set可以改动,也不建议将它改的很大,因为一旦支持的文件描述多了,效率自然也就低了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值