zoukankan      html  css  js  c++  java
  • Linux IO多路复用 select

    Linux IO多路复用 select

    之前曾经写过简单的服务器,服务器是用多线程阻塞,客户端每一帧是用非阻塞实现的

    后来发现select可以用来多路IO复用,就是说可以把服务器这么多线程放在一个线程里面,减小资源消耗,没必要开多个线程

    不过实际上select使用很少,现在一般会用epoll这个函数

    我们先来看一下linux里面man手册对select的介绍

    可见select是个同步的io

    DESCRIPTION
    select() and pselect() allow a program to monitor multiple file
    descriptors, waiting until one or more of the file descriptors become
    "ready" for some class of I/O operation (e.g., input possible). A file
    descriptor is considered ready if it is possible to perform a corre‐
    sponding I/O operation (e.g., read(2) without blocking, or a suffi‐
    ciently small write(2)).

    翻译过来大概的意思就是这个函数可以监视已经准备好的文件描述符,然后对他们进行读写

    再来看一下函数原型

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

    第一个参数是监听最大文件描述符 (一般是maxfd+1,从0开始算)

    接下来三个分别是读,写,异常的fd_set

    fd_set是文件描述符集合

    最后一个是超时时间设NULL为无限等待

    当然,我们一般是用宏定义来操作fdset FD_ZERO FD_CLR FD_SET FD_IISET

    void FD_CLR(int fd, fd_set *set);//清除一个文件描述符
    int  FD_ISSET(int fd, fd_set *set);//测试一个文件描述符
    void FD_SET(int fd, fd_set *set);//添加一个
    void FD_ZERO(fd_set *set);//全都设为 0
    //不要被手册迷惑,这个是宏定义,使用的时候要注意
    

    这个其实就是用数组实现的

    32位系统: /usr/include/i386-linux-gnu/sys
    64位系统: /usr/include/x86_64-linux-gnu/sys/
    

    具体使用:

        fd_set rfds;
        struct timeval tv;
        int retval;
    
        /* Watch stdin (fd 0) to see when it has input. */
        FD_ZERO(&rfds);
        FD_SET(0, &rfds);
    
        /* Wait up to five seconds. */
        tv.tv_sec = 5;
        tv.tv_usec = 0;
    
        retval = select(1, &rfds, NULL, NULL, &tv);
        /* Don't rely on the value of tv now! */
    
        if (retval == -1)
            perror("select()");
        else if (retval)
            printf("Data is available now.\n");
        /* FD_ISSET(0, &rfds) will be true. */
        else
            printf("No data within five seconds.\n");
    
    

    缺点:

    1. 有上限 linux 1024 (fd_set 是数组实现的,肯定有上限)
    2. 每次监听的时候涉及到数组copy到内核,监听较多文件描述符时候可能会性能下降
    3. 内核完成的时候也会涉及到copy
    4. select只能返回有几个文件描述符就绪,而不会告诉你具体是哪一个,需要遍历

    自己做做demo的时候还是挺好用的

    这里有两个实例,我觉得很容易看懂

    https://blog.csdn.net/fengel_cs/article/details/78645140

    https://www.cnblogs.com/luoxn28/p/6220372.html

    同步异步不过不太清除的可以具体看看这个文章,写的很好

    https://www.cnblogs.com/euphie/p/6376508.html

  • 相关阅读:
    Python之推导式笔记
    利用ShardingSphere-JDBC实现分库分表--配置中心的实现
    利用ShardingSphere-JDBC实现分库分表
    MGR安装记录
    学习RadonDB源码(三)
    学习RadonDB源码(二)
    学习RadonDB源码(一)
    Spring Cloud学习笔记--Spring Boot初次搭建
    一次单核CPU占用过高问题的处理
    MySQL AutoCommit带来的问题
  • 原文地址:https://www.cnblogs.com/stdpain/p/10657347.html
Copyright © 2011-2022 走看看