zoukankan      html  css  js  c++  java
  • select()函数

    原型:

    #include<sys/time.h>
    #include<unistd.h>
    int select(int maxfd, fd_set *rdset, fd_set *wrest, fd_set *exset, struct timeval *timeout);

    参数:

    • maxfd:描述需要监视最大文件描述符+1
    • rdset:监视的可读文件描述符的集合
    • wrset:监视的可写文件描述符的集合
    • exset:监视的异常文件描述符的集合
    • struct timeval:描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生,返回0

    返回值:

    • 超时返回0
    • 失败返回-1
    • 成功返回大于0的整数,这个整数表示就绪描述符的数目
    int FD_ZERO(fd_set *fdset):将指定的文件描述符集情况,在对文件描述符集合进行设置之前,必须对其进行初始化。如果不请空,由于在系统分配内存后,通常不做清空处理,所以结果时不可知的。
    int FD_SET(int fd, fd_set *fdset);    用于在文件描述符集合中添加一个新的文件描述符
    int FD_CLR(int fd, fd_set *fdset); 用于在文件描述符集合中删除一个新的文件描述符
    int FD_ISSET(int fd, fd_set *fdset); 用于测试指定的文件描述符是否在该集合中。

    注意:fd_set通常是一个整数数组,其中每个整数中的每一位对应一个描述符(矢量),例如,使用一个32位整数,那么该数组的第一个元素对应于描述符0~31,第二个元素对应于描述符32~63,一次类推。

    select 系统调用用途在于在一段指定的时间内,监听用户感兴趣的文件描述符上可读可写和异常事件。

    select使用范例:

    当声明了一个文件描述符集之后,必须用FD_ZERo将所有位置置0,然后再将我们所感兴趣的描述符所对应的位置位:

    1. fd_set rset;
    2. int fd;
    3. FD_ZERO(&rset);
    4. FD_SET(fd,&rset);
    5. FD_SET(stdin,&rset);

    然后调用select函数,阻塞等待文件描述符事件的到来如果超过设定的事件,则不再等待,继续往下执行

    select(fd+1,&rset,NULL,NULL,NULL);

    select返回后,用FD_ISSET测试给定位是否置位。

    if(FD_ISSET(fd, &rset))
    {
    …
        //do something
    }

    深入理解select模型:

    理解selecr模型的关键是在于理解fd_set为了说明方便,取fd_set长度为1字节,fd_set的每一位bit可以对应一个文件描述符,则1字节长的fd_set最大可以对应8个fd。

    1. 执行fd_set set; FD_ZERO(&set); 则set用位表示为 0000,0000
    2. 若fd = 5,执行FD_SET(fd,&set);      后set变为0001,0000 (第5位置1)
    3. 若再加入fd = 2,fd = 1,则set变为0001,0011
    4. 执行select(6,&set,0,0,0)阻塞等待
    5. 若fd=1,fd=2上有事件发生,则select返回,此时set变为0000,0001。注意:没有事件发生的fd=5被清空。

    select模型特点:

    1. 可监控的文件描述符个数取决于sizeof(fd_set)的值。每个bit可以表示一个文件描述符。
    2. 将fd加入到select监控集的同事,还要再使用一个数据结构array保存放到select监控集中的fd,一是用于在select返回后,array作为元数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但无事件发生的fd清空,则每次开始select前都要重新从array取得fd逐一加入人(FD_ZERO最先),扫描array的同时取得fd的最大值maxfd,用于select的第一个参数

    可见select模型必须在select前循环加上fd,取maxfd,select 返回后在利用FD_ISSET判断是否有事件发生。

     

    select优势:

    用户可以在一个线程内同时处理多个socket的IO请求,在网络编程中,当涉及到多客户访问服务器的情况,除了使用fork多个进程来处理每个客户的连接,还可以使用select来处理。

    select缺点:

    select本质是通过设置或者检查存放fd标志位的数据结构来进行下一步处理,这样带来的缺点:

    • l  单个进程可监视的fd数量被限制,即能监听端口的大小有限。一般来说这个数目和系统内存关系很大,具体数目可以cat /proc/sys/fs/file-max查看。
    • l  对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低,当套接字比较多的时候,每次select(0都要通过遍历FD_SETSIZE个socket来完成调度,不管哪个socket是活跃的,都需要遍历一遍。这就很浪费CPU事件,如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,这就避免了轮询,这正是epoll与kqueue做的
    • l  需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构体时赋值开销大。
  • 相关阅读:
    canvas上的像素操作(图像复制,细调)
    AMD、CMD、CommonJS 和 ES6 模块化规范
    JS垃圾回收
    函数式编程中如何处理副作用?
    vue中的$on,$emit,$once,$off源码实现
    重新学习react生命周期
    keep alive实现原理
    读取 url 参数方法
    使用Bootstratp Blazor +EF Codefirst 愉快的增删改查!
    记录一下爬取微信小程序视频的过程!
  • 原文地址:https://www.cnblogs.com/wanghao-boke/p/11655768.html
Copyright © 2011-2022 走看看