I/O复用---select

18 篇文章 0 订阅
17 篇文章 0 订阅
  I/O复用也是提高服务器性能的一种非常高效的方式,它的原理是什么呢?
  我们知道服务器在   接受新的客户端链接,接受已连接客户端发来的数据   等事情上不总是连续的,持续的。假如 一个服务器不使用多线程编程的话,只用一个main线程只能做到和一个客户端链接,接受数据。然而这个客户端只 和服务器链接一次,并且发送数据也不是特别频繁,特别持续的。那么这个服务器可以说是大部分时间在无谓的等待客户端,而不是高效的运作着。
    因此就有了一种想法,那就是把接受到客户端链接 ,接收到链接上发来的数据 这些事情称之为事件, 如果事件发生了,服务器才做出相应,不会一直和某个客户端干耗着。服务器也不必只维持和一个客户端的关系,而是哪个客户端有和服务器交流的需求,服务器就会满足它的需求,因此这样可以同时处理很多客户端。这就高效的利用了服务器,称之为I/O复用。
    至于具体怎么去对某些事件做出反应,我们慢慢来看,首先我们非常熟悉网络编程的开始都会创建一个socket,这个socket其实就是文件描述符,我们listen(sockfd)其实就是在内核上对套接字文件描述符进行监听,accept接受链接就是 从监听队列中发现了有一个客户端对  监听队列中的socket所绑定的服务器  发起了链接的事件。
  可以推出服务器和客户端的链接是发生在sockfd的文件描述符上的。 而链接上以后,返回了特定的链接描述符c,此时已经不需要socket了, recv/send的函数都是c为参数的,因此可以直到收发数据是发生在连接文件描述符上的。
    而I/O复用其实也就是监听描述符上发生的事情。本文先来说说select函数,select函数如下
   
  int select (int nfds,fd_set *readfds,fd_set *writefds,fd_set*exceptfds,struct timeval*timeout);
    第一个参数nfds就是被监听的文件描述符中最大值+1。假如监听描述符为4,5,6 那么此项就是7
    第二个参数至第四个参数分别为可读事件,可写事件,异常事件
    fd_set结构体如下

看起来复杂,其实本质来讲就是一个成员为long   fdset[32]的结构体,一个long为4个字节32bit,32个long就是1024bit,一个位表示一个描述符,因此最多可以监听1024个描述符,描述符取值0-1023

   最后一个参数为timeout为select等待事件发生的 时间
   timeval的 两个成员分别为long tv_sec  和long tv_usec 表示秒和微秒
   如果设置为NULL,那么将一直阻塞,直到 有时间发生;如果为0,就立即返回。

最后返回值是 -1出错,0超时,>0为就绪事件的个数

这个select的工作原理和fd_set有着很大的关联,是这样的,fd_set告诉我们可以监视1023以内的描述符,
我们一般先会把fd_set里的1024个bit全部初始为0
然后假如我们关注的是4 5 6这三个描述符,
那么内核 4 5 6这个三个描述符在fd_set里对应的位设置为1,表示我们关注的4 5 6
然后过了一会儿,我们要判断这个三个描述符上是否有事件发生了,如果有事件发生,那么内核就会把我们刚设置成1的位改为0,没有事件的话依旧为1,因此我们要把判断刚关注的几个位是否依旧为1,如果一旦某个位变成0了,就代表那个位对应的描述符发生了事件,我们就要对那个描述符进行处理。

为了简化操作,系统给出了几个宏来避免我们来写过于麻烦的位操作



依旧用一个服务器进程和多个客户端通讯来举例

服务器的流程是这样
socket
 bind 
 listen 
int fds[128];   //定义一个文件描述符数组来存放socket和c  , 范围0-1023之间。我按128来算
set_fd read;  //定义一个可读的set_fd
fds[0]=socket; //把socket先填入fds中,如果有多个,例如tcp和udp同时通信,要填入两个socket。

while
                FD_ZERO(&read);          //  每次循环第一件事都要清空fd_set,防止上一次循环的影响
                    
                 遍历128次,将fds中的描述符全部FD_SET(描述符,&read);  

                select
           
               遍历128次,如果FD_ISSET(描述符,&read)成立进入下面的代码段
                  
               {
                       如果是描述符是socket,那么代表有连接的事件,那么给fds[]中加入新的链接描述符

                       如果不是socket,则代表是c连接描述符,那么就进行收发数据。


              }



大体框架如上
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值