手机可以建设网站吗,wordpress扒皮,山东建设厅网站 高英,更改wordpress链接一、select函数
select函数是IO多路复用的函数#xff0c;它主要的功能是用来等文件描述符中的事件是否就绪#xff0c;select可以使我们在同时等待多个文件缓冲区 #xff0c;减少IO等待的时间#xff0c;能够提高进程的IO效率。
select()函数允许程序监视多个文件描述符…一、select函数
select函数是IO多路复用的函数它主要的功能是用来等文件描述符中的事件是否就绪select可以使我们在同时等待多个文件缓冲区 减少IO等待的时间能够提高进程的IO效率。
select()函数允许程序监视多个文件描述符等待所监视的一个或者多个文件描述符变为“准备好”的状态。所谓的”准备好“状态是指文件描述符不再是阻塞状态可以用于某类IO操作了包括可读可写发生异常三种
二、参数介绍 int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
ndfs
等待的文件描述符的最大值1例如应用进程想要去等待文件描述符3,5,8的事件则
nfdsmax(3,5,8)1;
fd_set类型
readfds和writefdsexceptfds的类型都是fd_set,那么fd_set类型是什么呢
fd_set类型本质是一个位图位图的位置 表示 相对应的文件描述符内容表示该文件描述符是否有效1代表该位置的文件描述符有效0则表示该位置的文件描述符无效。如果将文件描述符23设置位图当中则位图表示的是为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中知道哪些文件描述符的事件就绪. 4.Select服务器
如果是一个select服务器进程则服务器进程会不断的接收有新链接每个链接对应一个文件描述符如果想要我们的服务器能够同时等待多个链接的数据的到来我们监听套接字listen_sock读取新链接的时候我们需要将新链接的文件描述符保存到read_arrys数组中下次轮询检测的就会将新链接的文件描述符设置进readfds中如果有链接关闭则将相对应的文件描述符从read_arrys数组中拿走。
一张图看懂select服务器 简易版的select服务器
server.hpp文件:
#pragma once #includeiostream #includesys/socket.h #includesys/types.h #includenetinet/in.h #includestring.h using std::cout; using std::endl; #define BACKLOG 5 namespace sjp{ class server{ public: static int Socket(){ int socksocket(AF_INET,SOCK_STREAM,0); if(sock0) return sock; if(sock0) exit(-1);
W } static bool Bind(int sockfd,short int port){ struct sockaddr_in lock; memset(lock,\0,sizeof(lock)); lock.sin_familyAF_INET; lock.sin_porthtons(port); lock.sin_addr.s_addrINADDR_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 #includevector#includeserver.hpp#includeunistd.h#includetime.hnamespace Select{class select_server{private:int listen_sock;//监听套接字 int port; public: select_server(int _port):port(_port){} //初始化select_server服务器 void InitServer(){ listen_socksjp::server::Socket(); sjp::server::Bind(listen_sock,port); sjp::server::Listen(listen_sock); } void Run(){ std::vectorint readfds_arry(1024,-1);//readfds_arry保存读事件的文件描述符 readfds_arry[0]listen_sock;//将监听套接字保存进readfds_arry数组中 fd_set readfds; while(1){ FD_ZERO(readfds); int nfds0; //将read_arry数组中的文件描述符设置进程readfds_arry位图中 for(int i0;i1024;i) { if(readfds_arry[i]!-1){ FD_SET(readfds_arry[i],readfds); if(nfdsreadfds_arry[i]){nfdsreadfds_arry[i];}}}//调用select对readfds中的文件描述符进行等待数据switch(select(nfds1,readfds,NULL,NULL,NULL)){case 0://没有一个文件描述符的读事件就绪coutselect timeoutendl;break;case -1://select失败coutselect errorendl;default:{//有读事件发生Soluation(readfds_arry,readfds);break;}} }}void Soluation(std::vectorint readfds_arry,fd_set readfds){
W for(int i0;ireadfds_arry.size();i){if(FD_ISSET(readfds_arry[i],readfds)){if(readfds_arry[i]listen_sock){//有新链接到来struct sockaddr peer;socklen_t len; int newfdaccept(listen_sock,peer,len);coutnewfdendl;//将新链接设置进readfds_arry数组中AddfdsArry(readfds_arry,newfd);}else{//其他事件就绪char str[1024];int szrecv(readfds_arry[i],str,sizeof(str),MSG_DONTWAIT);switch(sz){case -1://读取失败coutreadfds_arry[i]: recv errorendl;break;case 0://对端关闭readfds_arry[i]-1;coutpeer closeendl;break;default:str[sz]\0;coutstrendl;break;}}}}}void AddfdsArry(std::vectorint fds_arry,int fd){
W for(int i0;ifds_arry.size();i){if(fds_arry[i]-1){fds_arry[i]fd;break;}}}};}
select_server.cc文件
#includeselect_server.hpp int main(int argv,char* argc[]){ if(argv!2){ cout./selectserver portendl; exit(-4); } int portatoi(argc[1]);//端口号Select::select_server* slnew Select::select_server(port); sl-InitServer(); sl-Run();
} 五.Select的缺陷
由于fd_set的上限是1024所以select能等待的读事件的文件描述符和写事件的文件描述是有上限的如果作为一个大型服务器能够同时链接的客户端是远远不够的。每次应用进程调用一次select之前都需要重新设定writefds和readfds如果进行轮询调用select这对影响cpu效率。内核每一次等待文件描述符 都会重新扫描所有readfds或者writefds中的所有文件描述符如果有较多的文件描述符则会影响效率。