使用select函数可以让开发者同时等待多个文件缓冲区,从而减少IO等待时间,提高进程的IO效率。select()函数是IO多路复用的函数,允许程序监视多个文件描述符,等待所监视的一个或者多个文件描述符变为“准备好”的状态;所谓的”准备好“状态是指:文件描述符不再是阻塞状态,可以用于某类IO操作了,包括可读,可写,发生异常三种。
#include<sys/select.h>头文件中包含了select函数,该函数可在计算机中进行调用。该函数用于监视文件描述符的变化情况——读写或是异常。
1.select函数介绍
select函数是IO多路复用的函数,它主要的功能是用来等文件描述符中的事件是否就绪,select可以使我们在同时等待多个文件缓冲区,减少IO等待的时间,能够提高进程的IO效率。
select()函数允许程序监视多个文件描述符,等待所监视的一个或者多个文件描述符变为“准备好”的状态。所谓的”准备好“状态是指:文件描述符不再是阻塞状态,可以用于某类IO操作了,包括可读,可写,发生异常三种
2.select函数参数的介绍
intselect(intnfds,fd_set*readfds,fd_set*writefds,
fd_set*exceptfds,structtimeval*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是等待读事件的文件描述符集合,.如果不关心读事件(缓冲区有数据),则可以传NULL值。
应用进程和内核都可以设置readfds,应用进程设置readfds是为了通知内核去等待readfds中的文件描述符的读事件.而内核设置readfds是为了告诉应用进程哪些读事件生效
writefds
与readfds类似,writefds是等待写事件(缓冲区中是否有空间)的集合,如果不关心写事件,则可以传值NULL。
exceptfds
如果内核等待相应的文件描述符发生异常,则将失败的文件描述符设置进exceptfds中,如果不关心错误事件,可以传值NULL。
设置select在内核中阻塞的时间,如果想要设置为非阻塞,则设置为NULL。如果想让select阻塞5秒,则将创建一个structtimevaltime={5,0};
其中structtimeval的结构体类型是:
};
返回值
如果没有文件描述符就绪就返回0;
如果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数组中拿走。
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
intsock=socket(AF_INET,SOCK_STREAM,0);
staticboolBind(intsockfd,shortintport){
intlisten_sock;//监听套接字
select_server(int_port):port(_port){}
//初始化select_server服务器
listen_sock=sjp::server::Socket();

sjp::server::Listen(listen_sock);
std::vector<int>readfds_arry(1024,-1);//readfds_arry保存读事件的文件描述符
readfds_arry[0]=listen_sock;//将监听套接字保存进readfds_arry数组中
//将read_arry数组中的文件描述符设置进程readfds_arry位图中
for(inti=0;i<1024;i++)
FD_SET(readfds_arry[i],&readfds);
if(nfds<readfds_arry[i]){
//调用select对readfds中的文件描述符进行等待数据
switch(select(nfds+1,&readfds,NULL,NULL,NULL)){
//没有一个文件描述符的读事件就绪
cout<<"selecttimeout"<<endl;
cout<<"selecterror"<<endl;
Soluation(readfds_arry,readfds);
voidSoluation(std::vector<int>&readfds_arry,fd_setreadfds){
W>for(inti=0;i<readfds_arry.size();i++){
if(FD_ISSET(readfds_arry[i],&readfds))
if(readfds_arry[i]==listen_sock){
intnewfd=accept(listen_sock,&peer,&len);
cout<<newfd<<endl;
//将新链接设置进readfds_arry数组中
AddfdsArry(readfds_arry,newfd);
intsz=recv(readfds_arry[i],&str,sizeof(str),MSG_DONTWAIT);
cout<<readfds_arry[i]<<":recverror"<<endl;
cout<<"peerclose"<<endl;
str[sz]='
#include"select_server.hpp"
intmain(intargv,char*argc[]){
cout<<"https://www.fruan.com/post/selectserverport"<<endl;
intport=atoi(argc[1]);//端口号
Select::select_server*sl=newSelect::select_server(port);
cout<<str<<endl;
voidAddfdsArry(std::vector<int>&fds_arry,intfd){
W>for(inti=0;i<fds_arry.size();i++){
lock.sin_port=htons(port);
lock.sin_addr.s_addr=INADDR_ANY;
if(bind(sockfd,(structsockaddr*)&lock,(socklen_t)sizeof(lock))<0){
staticboolListen(intsockfd){
if(listen(sockfd,BACKLOG)<0){
}
select_server.hpp文件
5.Select的缺陷由于fd_set的上限是1024,所以select能等待的读事件的文件描述符和写事件的文件描述是有上限的,如果作为一个大型服务器,能够同时链接的客户端是远远不够的。
每次应用进程调用一次select之前,都需要重新设定writefds和readfds,如果进行轮询调用select,这对影响cpu效率。
内核每一次等待文件描述符都会重新扫描所有readfds或者writefds中的所有文件描述符,如果有较多的文件描述符,则会影响效率。
以上就是linux要用select的原因是什么的详细内容,更多请关注主机测评网其它相关文章!
本文来源:国外服务器--linux要用select的原因是什么(linux中selinux的三种选项)
本文地址:https://www.idcbaba.com/guowai/4668.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 1919100645@qq.com 举报,一经查实,本站将立刻删除。



