IO多路复用之select

系统提供select函数来实现多路复用输入/输出模型。

select函数让我们的程序监视多个文件描述符的状态变化。程序会停在select这里等待,直到被监视的文件描述符中有一个或多个发生了状态变化


函数原型如下:

IO多路复用之select

返回值:   成功返回就绪描述符的个数,超过timeout时间且没有任何事件发生返回0,失败返回-1

参数解释:

nfds:    被监视的文件描述符中值最大描述符值加1(描述符是从0开始的,描述符0、1、2...nfds-1均将被测试

下面三个参数readset、writeset和exceptset指定我们要让内核测试读、写和异常条件的描述符。如果对某一个的条件不感兴趣,就可以把它设为空指针。

readfds:   读描述符集(所有关心读事件的描述符被用户添加进来),这个参数是个输入输出型参数

writefds:  写描述符集

exceptfds: 异常描述符集

struct fd_set可以理解为一个集合,这个集合中存放的是文件描述符,可通过以下四个宏进行设置:

 void FD_CLR(int fd, fd_set *fdset);   //把给定的文件描述符从指定集合删除

 int FD_ISSET(int fd, fd_set *fdset);  //判断指定描述符时候被加入了指定集合中(是否可读/可写) 

 void FD_SET(int fd, fd_set *fdset);   //把一个给定的文件描述符加入集合之中

 void FD_ZERO(fd_set *fdset);           //清空集合

timeout:   设置一段时间

(1)timeout=NULL时,当前进程一直等待,直到有一个描述符准备好I/O(永远等下去)

(2)timeout指向timeval结构体且时间设置不为0时,当前进程挂起,如果到了设定的时间(timeout)还没有任何事件发生就返回0,进程继续执行后面的代码(等待一段固定时间)

(3)timeout指向timeval结构体且时间设置为0时,不会等待,立即返回(根本不等待)

                      struct timeval{

                                       long tv_sec;   //seconds

                                       long tv_usec;  //microseconds

                               };

server_select.c

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #define BLOCK 6 int fds[64]; void usage(char * proc) {     printf("%s [ip] [port]\n",proc); } int create_sock(char *port,const char * inaddr) {     //1.     int listenfd=socket(AF_INET,SOCK_STREAM,0);     if(listenfd<-1){         perror("listenfd");         exit(1);     }     //2.     struct sockaddr_in local;     local.sin_family=AF_INET;     int _port=atoi(port);     local.sin_port=htons(_port);     local.sin_addr.s_addr=inet_addr(inaddr);     struct linger lig;     int iLen;     lig.l_onoff=1;     lig.l_linger=0;     iLen=sizeof(struct linger);     setsockopt(listenfd,SOL_SOCKET,SO_LINGER,(char *)&lig,iLen);     //3.     if(bind(listenfd,(struct sockaddr*)&local,sizeof(local))<0){         perror("bind");         exit(2);     }     //4.     if(listen(listenfd,BLOCK)<0){         perror("listen");         exit(3);     }     return listenfd; } int main(int argc,char* argv[]) {     if(argc!=3){         usage(argv[0]);         exit(1);     }     //create listenfd     int listen_fd=create_sock(argv[2],argv[1]);     struct sockaddr_in client;     socklen_t len=sizeof(client);     int max_fd=listen_fd;     char buf[1024];     //initialize fds[]     int fds_num=sizeof(fds)/sizeof(fds[0]);     int i=0;     for(i=0;i<fds_num;++i){         fds[i]=-1;     }     fds[0]=listen_fd;     int done=0;     while(!done){             //define and initialize parameter of select()              fd_set readset;             FD_ZERO(&readset);             FD_SET(listen_fd,&readset);                  fd_set writeset;             FD_ZERO(&writeset);                  struct timeval timeout;             timeout.tv_sec=5;             timeout.tv_usec=0;                          //             for(i=1;i<fds_num;++i){                 if(fds[i]>0){                     FD_SET(fds[i],&readset);                     FD_SET(fds[i],&writeset);                     if(fds[i]>max_fd)                         max_fd=fds[i];                 }                 else                     break;             }         switch(select(max_fd+1,&readset,&writeset,NULL,&timeout)){         //switch(select(max_fd+1,&readset,NULL,NULL,&timeout)){             case -1:                 perror("select");                 break;             case 0:                 printf("timeout...\n");                 break;             default:                 for(i=0;i<fds_num;++i){                  //listen_fd happen                     if(fds[i]==listen_fd && FD_ISSET(fds[i],&readset)){                         int connfd=accept(listen_fd,(struct sockaddr*)&client,&len);                         if(connfd<0){                             perror("accept");                             break;                         }else{                             printf("get a connect...\n");                             for(i=0;i<fds_num;++i){                                 if(fds[i]==-1){                                     fds[i]=connfd;                                     break;                                 }                             }                         }                     }                     //normal event happen                     else if(fds[i]>0 && FD_ISSET(fds[i],&readset)){                             ssize_t _size=read(fds[i],buf,sizeof(buf)-1);                             if(_size<0){                                 perror("read");                             }else if(_size==0){//client closed                                 printf("client shutdown...\n");                                 close(fds[i]);                                 fds[i]=-1;                                 continue;                             }else{                                 buf[_size]='\0';                                 printf("client# %s",buf);                                 if(FD_ISSET(fds[i],&writeset)){                                     if(write(fds[i],buf,sizeof(buf)-1)<0){                                         perror("write");                                     }                                 }                             }                                                  }                     else{                     }                 }                 break;         }     }        return 0; }


郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。