我的编程空间,编程开发者的网络收藏夹
学习永远不晚

【Linux】——select详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

【Linux】——select详解

  • 💂 个人主页:努力学习的少年
  • 🤟 版权: 本文由【努力学习的少年】原创、在CSDN首发、需要转载请联系博主
  • 💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦

目录

1. select函数介绍

2. select函数参数的介绍

3.select的工作流程

4.Select服务器

5.Select的缺陷


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;                        long    tv_usec;                   };

返回值

  • 如果没有文件描述符就绪就返回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);    W>    }                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){W>        for(int i=0;i& fds_arry,int fd){W>        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中的所有文件描述符,如果有较多的文件描述符,则会影响效率。

来源地址:https://blog.csdn.net/sjp11/article/details/126312199

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

【Linux】——select详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

linux使用select实现精确定时器详解

在编写程序时,我们经常会用到定时器。首先看看select函数原型如下: int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exc
2022-06-04

SQL SELECT TOP 子句详解

在SQL语句中,使用SELECT TOP子句可以限制查询结果返回的记录数。语法:SELECT TOP 行数|百分比 列名FROM 表名WHERE 条件;其中,行数表示要返回的记录数,百分比表示要返回的记录数与总记录数的百分比。可以使用整数值
2023-09-13

SELECT INTO 和 INSERT INTO SELECT 两种表复制语句详解

SELECT INTO 和 INSERT INTO SELECT 是在 SQL 中用于复制表的两种语句。1. SELECT INTO:SELECT INTO 语句用于创建一个新的表,并从一个已有的表中复制数据。语法如下:SELECT * I
2023-08-14

Mysql的SELECT语句与显示表结构详解

SELECT...SELECT 1+1, 2+2;# 直接这样写相当于下面这句SELECT 1+1, 2+2 FROM DUAL; # 这里DUAL:伪表SELECT ... FROM语法:SELECT 标识选择哪些字段(列)FRO
2023-01-28

select into from和insert into select的使用举例详解

目录1. SELECT INTO 语句1.1 SELECT INTO 语法2. INSERT INTO SELECT 语句2.1 INSERT INTO SELECT 语法3. select into from 和 insert into
2023-04-21

编程热搜

目录