linux要用select的原因是什么
使用select函数可以让开发者同时等待多个文件缓冲区,从而减少IO等待时间,提高进程的IO效率。select()函数是IO多路复用的函数,允许程序监视多个文件描述符,等待所监视的一个或者多个文件描述符变为“准备好”的状态;所谓的”准备好“状态是指:文件描述符不再是阻塞状态,可以用于某类IO操作了,包括可读,可写,发生异常三种。
#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<iostream> #include<sys/socket.h> #include<sys/types.h> #include<netinet/in.h> #include<string.h> 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<vector> #include"server.hpp" #include<unistd.h> #include<time.h> 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<int> 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[i]){ nfds=readfds_arry[i]; } } } //调用select对readfds中的文件描述符进行等待数据 switch(select(nfds+1,&readfds,NULL,NULL,NULL)){ case 0: //没有一个文件描述符的读事件就绪 cout<<"select timeout"<<endl; break; case -1: //select失败 cout<<"select error"<<endl; default: { //有读事件发生 Soluation(readfds_arry,readfds); break; } } } } void Soluation(std::vector<int>& readfds_arry,fd_set readfds){ W> for(int i=0;i<readfds_arry.size();i++){ if(FD_ISSET(readfds_arry[i],&readfds)) { if(readfds_arry[i]==listen_sock){ //有新链接到来 struct sockaddr peer; socklen_t len; int newfd=accept(listen_sock,&peer,&len); cout<<newfd<<endl; //将新链接设置进readfds_arry数组中 AddfdsArry(readfds_arry,newfd); } else{ //其他事件就绪 char str[1024]; int sz=recv(readfds_arry[i],&str,sizeof(str),MSG_DONTWAIT); switch(sz){ case -1: //读取失败 cout<<readfds_arry[i]<<": recv error"<<endl; break; case 0: //对端关闭 readfds_arry[i]=-1; cout<<"peer close"<<endl; break; default: str[sz]='\0'; cout<<str<<endl; break; } } } } } void AddfdsArry(std::vector<int>& fds_arry,int fd){ W> for(int i=0;i<fds_arry.size();i++){ if(fds_arry[i]==-1){ fds_arry[i]=fd; break; } } } }; }
select_server.cc文件
#include"select_server.hpp" int main(int argv,char* argc[]){ if(argv!=2){ cout<<"./selectserver port"<<endl; exit(-4); } int port=atoi(argc[1]);//端口号 Select::select_server* sl=new Select::select_server(port); sl->InitServer(); sl->Run(); }
测试:
5.Select的缺陷
由于fd_set的上限是1024,所以select能等待的读事件的文件描述符和写事件的文件描述是有上限的,如果作为一个大型服务器,能够同时链接的客户端是远远不够的。
每次应用进程调用一次select之前,都需要重新设定writefds和readfds,如果进行轮询调用select,这对影响cpu效率。
内核每一次等待文件描述符 都会重新扫描所有readfds或者writefds中的所有文件描述符,如果有较多的文件描述符,则会影响效率。
以上是linux要用select的原因是什么的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

DeepSeek 是一款强大的智能搜索与分析工具,提供网页版和官网两种访问方式。网页版便捷高效,免安装即可使用;官网则提供全面产品信息、下载资源和支持服务。无论个人还是企业用户,都可以通过 DeepSeek 轻松获取和分析海量数据,提升工作效率、辅助决策和促进创新。

DeepSeek的安装方法有多种,包括:从源码编译(适用于经验丰富的开发者)使用预编译包(适用于Windows用户)使用Docker容器(最便捷,无需担心兼容性)无论选择哪种方法,请仔细阅读官方文档并充分准备,避免不必要的麻烦。

如何下载BitPie比特派钱包App?步骤如下:在AppStore(苹果设备)或GooglePlay商店(安卓设备)中搜索“BitPie比特派钱包”。点击“获取”或“安装”按钮下载应用程序。对于电脑版,访问BitPie比特派钱包官方网站并下载相应软件包。

BITGet 是一款加密货币交易所,提供各种交易服务,包括现货交易、合约交易和衍生品。该交易所成立于 2018 年,总部位于新加坡,致力于为用户提供安全可靠的交易平台。BITGet 提供多种交易对,包括 BTC/USDT、ETH/USDT 和 XRP/USDT。此外,该交易所还在安全性和流动性方面享有盛誉,并提供多种功能,如高级订单类型、杠杆交易和 24/7 全天候客户支持。

欧易 OKX,全球领先的数字资产交易所,现推出官方安装包,提供安全便捷的交易体验。欧易 OKX 安装包无需通过浏览器访问,可直接在设备上安装独立应用程序,为用户打造稳定高效的交易平台。安装过程简便易懂,用户只需下载最新版本安装包,按照提示一步步操作即可完成安装。

Gate.io是一款受欢迎的加密货币交易所,用户可通过下载其安装包并安装在设备上使用。获取安装包步骤如下:访问Gate.io官方网站,点击“下载”,选择对应操作系统(Windows、Mac或Linux),将安装包下载至计算机。安装过程中建议暂时禁用杀毒软件或防火墙,确保安装顺利。完成后,用户需创建Gate.io账户以开始使用。

欧易,又称OKX,是一个全球领先的加密货币交易平台。文章提供了欧易官方安装包的下载入口,方便用户在不同设备上安装欧易客户端。该安装包支持 Windows、Mac、Android 和 iOS 系统,用户可根据自己的设备类型选择相应版本下载。安装完成后,用户即可注册或登录欧易账户,开始交易加密货币和享受平台提供的其他服务。

Gate.io 是一款备受赞誉的加密货币交易平台,以其广泛的代币选择、低廉的交易费用和用户友好的界面而闻名。凭借其先进的安全功能和优秀的客户服务,Gate.io 为交易者提供一个可靠且便利的加密货币交易环境。想要加入 Gate.io 的行列,欢迎点击提供的链接下载官方注册安装包,开启您的加密货币交易之旅。
