linux为什么要用select

发布时间 - 2023-01-30 00:00:00    点击率:
因为select可以使开发者在同时等待多个文件缓冲区,可减少IO等待的时间,能够提高进程的IO效率。select()函数是IO多路复用的函数,允许程序监视多个文件描述符,等待所监视的一个或者多个文件描述符变为“准备好”的状态;所谓的”准备好“状态是指:文件描述符不再是阻塞状态,可以用于某类IO操作了,包括可读,可写,发生异常三种。

本教程操作环境:linux7.3系统、Dell G3电脑。

select是一个计算机函数,位于头文件#include 。该函数用于监视文件描述符的变化情况——读写或是异常。

1. select函数介绍

select函数是IO多路复用的函数,它主要的功能是用来等文件描述符中的事件是否就绪,select可以使我们在同时等待多个文件缓冲区 ,减少IO等待的时间,能够提高进程的IO效率。

select()函数允许程序监视多个文件描述符,等待所监视的一个或者多个文件描述符变为“准备好”的状态。所谓的”准备好“状态是指:文件描述符不再是阻塞状态,可以用于某类IO操作了,包括可读,可写,发生异常三种

2. select函数参数的介绍

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

ndfs

等待的文件描述符的最大值+1,例如:应用进程想要去等待文件描述符3,5,8的事件,则

nfds=max(3,5,8)+1;

fd_set类型

readfds和writefds,exceptfds的类型都是fd_set,那么fd_set类型是什么呢?

  • fd_set类型本质是一个位图位图的位置 表示 相对应的文件描述符,内容表示该文件描述符是否有效,1代表该位置的文件描述符有效,0则表示该位置的文件描述符无效。
  • 如果将文件描述符2,3设置位图当中,则位图表示的是为1100。
  • fd_set的上限是1024个文件描述符。

readfds

  • readfds是 等待读事件的文件描述符集合,.如果不关心读事件(缓冲区有数据),则可以传NULL值。
  • 应用进程和内核都可以设置readfds,应用进程设置readfds是为了通知内核去等待readfds中的文件描述符的读事件.而 内核设置readfds是为了告诉应用进程哪些读事件生效

writefds

与readfds类似,writefds是等待写事件(缓冲区中是否有空间)的集合,如果不关心写事件,则可以传值NULL。

exceptfds

如果内核等待相应的文件描述符发生异常,则将失败的文件描述符设置进exceptfds中,如果不关心错误事件,可以传值NULL。

timeout

设置select在内核中阻塞的时间,如果想要设置为非阻塞,则设置为NULL。如果想让select阻塞5秒,则将创建一个struct timeval time={5,0};

其中struct timeval的结构体类型是:

           struct timeval {
               long    tv_sec;         /* seconds */
               long    tv_usec;        /* microseconds */
           };

返回值

  • 如果没有文件描述符就绪就返回0;
  • 如果调用失败返回-1;
  • 如果timeout中中readfds中有事件发生,则返回timeout剩下的时间。

3.select的工作流程

应用进程内核都需要从readfds和writefds获取信息,其中,内核需要从readfds和writefds知道哪些文件描述符需要等待,应用进程需要从readfds和writefds中知道哪些文件描述符的事件就绪.

如果我们要不断轮询等待文件描述符,则应用进程需要不断的重新设置readfds和writefds,因为每一次调用select,内核会修改readfds和writefds,所以我们需要在 应用程序设置一个数组 来保存程序需要等待的文件描述符,保证调用 select 的时候readfds 和 writefds中的将如下:

4.Select服务器

 如果是一个select服务器进程,则服务器进程会不断的接收有新链接每个链接对应一个文件描述符,如果想要我们的服务器能够同时等待多个链接的数据的到来,我们监听套接字listen_sock读取新链接的时候,我们需要将新链接的文件描述符保存到read_arrys数组中,下次轮询检测的就会将新链接的文件描述符设置进readfds中,如果有链接关闭,则将相对应的文件描述符从read_arrys数组中拿走

一张图看懂select服务器:

简易版的select服务器:

server.hpp文件:

#pragma once  
  #include
  #include
  #include    
  #include 
  #include
  using std::cout;
  using std::endl;
  #define BACKLOG 5  
      
  namespace sjp{    
    class server{    
      public:    
      static int Socket(){    
        int sock=socket(AF_INET,SOCK_STREAM,0);    
        if(sock>0)    
        return sock;    
        if(sock<0)    
          exit(-1);    
   }    
      
      static bool Bind(int sockfd,short int port){    
        struct sockaddr_in lock;    
        memset(&lock,'\0',sizeof(lock));    
        lock.sin_family=AF_INET;    
        lock.sin_port=htons(port);    
        lock.sin_addr.s_addr=INADDR_ANY;    
        if(bind(sockfd,(struct sockaddr*)&lock,(socklen_t)sizeof(lock))<0){    
                  exit(-2);
        }    
        return true;    
      }    

     static bool Listen(int sockfd){
        if(listen(sockfd,BACKLOG)<0){
          exit(-3);
        }
        return true;
      }
    };
  }

 select_server.hpp文件

#pragma once
  #include
  #include"server.hpp"
  #include
  #include
  
  namespace Select{
    class select_server{
      private:
        int listen_sock;//监听套接字    
        int port;    
          
      public:    
        select_server(int _port):port(_port){}    
      
        //初始化select_server服务器    
        void InitServer(){    
          listen_sock=sjp::server::Socket();    
          sjp::server::Bind(listen_sock,port);    
          sjp::server::Listen(listen_sock);    
        }    
      
      
        void Run(){    
          std::vector readfds_arry(1024,-1);//readfds_arry保存读事件的文件描述符    
          readfds_arry[0]=listen_sock;//将监听套接字保存进readfds_arry数组中    
          fd_set readfds;    
          while(1){    
          FD_ZERO(&readfds);    
          int nfds=0;    
          //将read_arry数组中的文件描述符设置进程readfds_arry位图中    
          for(int i=0;i<1024;i++)    
          {    
            if(readfds_arry[i]!=-1){    
            FD_SET(readfds_arry[i],&readfds);    
           if(nfds& readfds_arry,fd_set readfds){
        for(int i=0;i& fds_arry,int fd){
       for(int i=0;i

 select_server.cc文件

#include"select_server.hpp"

int main(int argv,char* argc[]){
  if(argv!=2){
    cout<<"./selectserver port"<InitServer();
  sl->Run();
}

测试:

5.Select的缺陷

  • 由于fd_set的上限是1024,所以select能等待的读事件的文件描述符和写事件的文件描述是有上限的,如果作为一个大型服务器,能够同时链接的客户端是远远不够的。
  • 每次应用进程调用一次select之前,都需要重新设定writefds和readfds,如果进行轮询调用select,这对影响cpu效率。
  • 内核每一次等待文件描述符 都会重新扫描所有readfds或者writefds中的所有文件描述符,如果有较多的文件描述符,则会影响效率。

推荐学习:Linux视频教程


# linux  # NULL  # select  # include  # 结构体  # Struct  # 事件  # 多个  # 是一个  # 组中  # 不关心  # 是指  # 作了  # 三种  # 则可  # 设置为  # 相对应 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 实例解析angularjs的filter过滤器  免费网站制作appp,免费制作app哪个平台好?  jquery插件bootstrapValidator表单验证详解  详解Oracle修改字段类型方法总结  进行网站优化必须要坚持的四大原则  如何基于PHP生成高效IDC网络公司建站源码?  Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】  安克发布新款氮化镓充电宝:体积缩小 30%,支持 200W 输出  Microsoft Edge如何解决网页加载问题 Edge浏览器加载问题修复  大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?  儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?  Laravel如何使用Gate和Policy进行权限控制_Laravel权限判定与策略规则配置  如何快速登录WAP自助建站平台?  如何使用 jQuery 正确渲染 Instagram 风格的标签列表  详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)  高端智能建站公司优选:品牌定制与SEO优化一站式服务  大连网站制作公司哪家好一点,大连买房网站哪个好?  详解Nginx + Tomcat 反向代理 负载均衡 集群 部署指南  Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验  Laravel storage目录权限问题_Laravel文件写入权限设置  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  Laravel如何正确地在控制器和模型之间分配逻辑_Laravel代码职责分离与架构建议  Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】  长沙做网站要多少钱,长沙国安网络怎么样?  Laravel项目结构怎么组织_大型Laravel应用的最佳目录结构实践  香港服务器部署网站为何提示未备案?  阿里云高弹*务器配置方案|支持分布式架构与多节点部署  Laravel如何使用Service Container和依赖注入?(代码示例)  长沙企业网站制作哪家好,长沙水业集团官方网站?  Android Socket接口实现即时通讯实例代码  HTML透明颜色代码怎么让下拉菜单透明_下拉菜单透明背景指南【技巧】  使用C语言编写圣诞表白程序  Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】  Laravel怎么创建自己的包(Package)_Laravel扩展包开发入门到发布  Laravel如何理解并使用服务容器(Service Container)_Laravel依赖注入与容器绑定说明  UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】  Laravel如何自定义错误页面(404, 500)?(代码示例)  php读取心率传感器数据怎么弄_php获取max30100的心率值【指南】  Laravel如何使用Collections进行数据处理?(实用方法示例)  厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?  Laravel Eloquent模型如何创建_Laravel ORM基础之Model创建与使用教程  Win11搜索栏无法输入_解决Win11开始菜单搜索没反应问题【技巧】  简单实现Android文件上传  Laravel如何配置.env文件管理环境变量_Laravel环境变量使用与安全管理  为什么php本地部署后css不生效_静态资源加载失败修复技巧【技巧】  湖南网站制作公司,湖南上善若水科技有限公司做什么的?  Laravel如何实现全文搜索_Laravel Scout集成Algolia或Meilisearch教程  EditPlus中的正则表达式 实战(4)  Laravel如何使用Livewire构建动态组件?(入门代码)  网站建设整体流程解析,建站其实很容易!