IO复用------select

IO复用

IO多路复用实际就是select/poll/epoll这些多路选择器,使用一个线程同时监听多个文件描述符(fd_set), I/O事件,阻塞等待并且在某个文件描述符可读写时收到通知。linux在处理网络IO连接时的优化,复用的不是I/O连接,而是复用的是线程,让一个线程处理多个连接。

Select

函数原型

int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,
struct timeval *timeout);

参数解释

nfds
委托内核检测的这三个集合中最大的文件描述符 + 1
内核需要线性遍历这些集合中的文件描述符,这个值是循环结束的条件。
readfds
文件描述符的集合,内核只检测这个集合中文件描述符对应的读缓冲区
传入传出参数,读集合一般情况下都是需要检测的,这样才知道通过哪个文件描述符接收数据
writefds
文件描述符的集合,内核只检测这个集合中文件描述符对应的写缓冲区
传入传出参数,如果不需要使用这个参数可以指定为 NULL
exceptfds
文件描述符的集合,内核检测集合中文件描述符是否有异常状态
传入传出参数,如果不需要使用这个参数可以指定为 NULL
timeout
超时时长,用来强制解除 select () 函数的阻塞的
将timeout设置为NULL:函数检测不到就绪的文件描述符会一直阻塞。
等待固定时长(秒):函数检测不到就绪的文件描述符,在指定时长之后强制解除阻塞,函数返回 0不等待:函数不会阻塞,直接将该参数对应的结构体初始化为 0 即可。
返回值
负值:select错误
0:等待超时,没有可读写或错误的文件
正值:有文件可读,或可写,或可读可写

fd_set集合

在这里插入图片描述
就是一个类似于数组,有1024位,如果设置文件描述符该位就为1。

编程流程

在这里插入图片描述

伪代码如下
fd_set se;
FD_ZERO(&se);//将se这个集合全部置为零
//设fd为用于监听的文件描述符
//将fd加入读集合中
FD_SET(fd,&se);
//设置select检测时间5秒
struct timeval timeout={5,0};
//while循环检测select中就绪的文件描述符
while(1){
 int num=select(1024,&se,NULL,NULL,);//我们只关心读事件,将写事件和异常事件集合置为空
 if(num<0){
   printf("select error\n");//select返回值小于0,执行函数失败
 }
 else if(num==0){
 printf("time out\n");
 }
 else{
 /*
 select返回值大于0表示有num个文件描述符就绪,我们需要
 遍历se找到用于监听的文件描述符fd和用于通信的文件描述符c。
 */
   for(int i=0;i<1024;++i){
   
     //找到用于监听的文件描述符fd我们需要accept接受
     if(FD_ISSET(fd,&se))
     {int c=accept(fd,struct sockarr*)&caddr,&len);
     //将用于通信的文件描述符c加入到se集合中等待下一轮select检测。
     FD_SET(c,&se);}

     //找到用于通信的文件描述符我们recv接受它
     if(FD_ISSET(i,&se)&&!FD_ISSET(fd,&se))
     {int len=recv(c,buff,127,0);
      if(len==0)//说明对方关闭,需要把通信文件描述符c从集合中取出
      FD_CLR(i,&se);
      close(i);}
   }
 }
}

Select弊端

从上述流程可以看出select需要把se不停的从用户态拷贝到内核态,select每次都会改变内核中的句柄数据结构集(fd集合),因而每次调用select都需要从用户空间向内核空间复制所有的句柄数据结构(fd集合),产生巨大的开销。最多支持1024个文件描述符。
select返回的是int,可以理解为返回的是准备好的一个或者多个文件描述符,应用程序需要遍历整个文件描述符数组才能发现哪些fd句柄发生了事件,由于select采用轮询的方式扫描文件描述符(不知道那个文件描述符读写数据,所以需要把所有的fd都遍历),文件描述符数量越多,性能越差。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值