溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

用select實(shí)現(xiàn)IO的復(fù)用

發(fā)布時(shí)間:2020-05-31 13:35:56 來(lái)源:網(wǎng)絡(luò) 閱讀:462 作者:yayaru9240 欄目:網(wǎng)絡(luò)安全

select系統(tǒng)調(diào)用用于一次監(jiān)控多個(gè)句柄(文件描述符)的狀態(tài)變化的。程序會(huì)停在select處等待,直到被監(jiān)視的句柄有一個(gè)或多個(gè)發(fā)生了狀態(tài)改變。

select函數(shù)原型:

int select(int nfds, fd_set *readfds, fd_set *writefd,fd_set *exceptfds, struct timeval *timeout);

nfds:表示文件描述符集的個(gè)數(shù)

readfds:當(dāng)前有多少個(gè)讀事件(有數(shù)據(jù)到了這個(gè)狀態(tài)稱之為讀事件)

writefd:當(dāng)前有多少個(gè)寫(xiě)事件(關(guān)心輸出緩沖區(qū)是否已滿)
最后一個(gè)結(jié)構(gòu)體表示每個(gè)幾秒鐘醒來(lái)做其他事件,用來(lái)設(shè)置select等待時(shí)間

函數(shù)返回值:

執(zhí)行成功返回描述符集當(dāng)中狀態(tài)已改變的個(gè)數(shù)

返回0表示在描述符狀態(tài)改變前已經(jīng)timeout

返回-1表示有錯(cuò)誤發(fā)生,可能為某個(gè)套接字的帶有外數(shù)據(jù)到達(dá)

關(guān)于select函數(shù)的相關(guān)函數(shù)操作

FD_CLR(inr fd,fd_set* set);來(lái)清除描述詞組set中相關(guān)fd 的位 

FD_ISSET(int fd,fd_set *set);判斷該文件描述符是否在當(dāng)前文件描述符集中 

FD_SET(int fd,fd_set*set);將該描述符設(shè)置到當(dāng)前文件描述符集中 

FD_ZERO(fd_set *set);可以用來(lái)初始化文件描述符集

select模型中的fd_set,例:若fd_set為1字節(jié),共有8位,則它的每一個(gè)位都可以對(duì)應(yīng)一個(gè)文件描述符,若fd=1則應(yīng)為0000 0001

將fd加入select監(jiān)控集時(shí),要用一個(gè)數(shù)組保存放到select監(jiān)控集中的文件描述符,為了在select 返回后,該數(shù)組中保存的數(shù)據(jù)可以和fd_set進(jìn)行FD_ISSET判斷,select在返回后會(huì)把以前加入的但并無(wú)任何事件發(fā)生的fd清空,每次開(kāi)始select前都要重新從數(shù)組取得fd

逐一加入。

使用select實(shí)現(xiàn)TCP通信

服務(wù)器端:

1 #include<stdio.h>
  2 #include<string.h>
  3 #include<errno.h>
  4 #include<sys/select.h>
  5 #include<stdlib.h>
  6 #include<netinet/in.h>
  7 #include<unistd.h>
  8 #include<arpa/inet.h>
  9 #include<sys/socket.h>
 10 int fileds[64]; //用一個(gè)數(shù)組保存select監(jiān)控集中的文件描述符
 11 void Usage(const char* proc)
 12 {
 13     printf("Usage:%s [ip] [port]\n",proc);
 14 }
 15 
 16 int start(int port,char* ip)
 17 {
 18     int listen_sock=socket(AF_INET,SOCK_STREAM,0);
 19     if(listen_sock<0)
 20     {
 21         perror("socket");
 22         exit(1);
 23     }
  24     struct sockaddr_in local;
 25     local.sin_family=AF_INET;
 26     local.sin_port=htons(port);
 27     local.sin_addr.s_addr=inet_addr(ip);
 28     socklen_t len=sizeof(local);
 29     if(bind(listen_sock,(struct sockaddr*)&local,len)<0)
 30     {
 31         perror("bind");
 32         exit(2);
 33     }
 34     if(listen(listen_sock,5)<0)
 35     {
 36         perror("listen");
 37         exit(3);
 38     }
 39     return listen_sock;
 40 }
 41 int main(int argc,char* argv[])
 42 {
 43     if(argc!=3)
  44     {
 45         Usage(argv[0]);
 46         exit(1);
 47     }
 48     char* _ip=argv[1];
 49     int _port=atoi(argv[2]);
 50     int listen_sock=start(_port,_ip);//create socket
 51     int newsock=-1;
 52     int max_fd=0;
 53     fd_set _reads;//many of read event
 54     fd_set _writes;//many of write event
 55     struct sockaddr_in client;
 56     int fds_count=sizeof(fileds)/sizeof(fileds[0]);
 57     socklen_t len=sizeof(client);
 58     int i=0;
 59     while(i<fds_count)
 60     {
 61         fileds[i]=-1; //init fileds[]
 62         ++i;
 63     }
 64     fileds[0]=listen_sock;
 65     max_fd=fileds[0];//init maxfd
 66     int done=0;
 67     while(!done)
 68     {
 69         FD_ZERO(&_reads); //每次循環(huán)進(jìn)來(lái)都要進(jìn)行初始化
 70         FD_ZERO(&_writes);
 71         FD_SET(listen_sock,&_reads);//set listen_sock to reads fd
 72         struct timeval _timeout;
 73         _timeout.tv_sec=20;
 74         _timeout.tv_usec=0;
 75         for(i=1;i<fds_count;++i)
 76         {
 77             if(fileds[i]>0)
 78             {
 79                 FD_SET(fileds[i],&_reads);
 80                 if(fileds[i]>max_fd)
 81                 {
 82                     max_fd=fileds[i];
 83                 }
 84             }
 85         }
 86         switch(select(max_fd+1,&_reads,NULL,NULL,&_timeout))
 87         {//the return val is how many fd is ready 
 88             case 0: //timeout
 89                 printf("select is timeout\n");
 90                 break;
 91             case -1://error
 92                 perror("select");
 93                 break;
 94             default:  //less than 1 fd is ready
 95             {
 96                 for(i=0;i<fds_count;++i)
 97                 {
 98                     if(fileds[i]==listen_sock \
 99                         && FD_ISSET(fileds[i],&_reads))
100                     {//listen_sock is ready  
101                         newsock=accept(listen_sock,(struct sockaddr*)&client    ,&(len));
102                         if(newsock<0)
103                         {
104                             perror("accept");
105                             return 1;
106                         }
107                         printf("get a new connect... [fd:%d],[ip:%s]\n",news    ock,inet_ntoa(client.sin_addr));
108                         for(i=0;i<fds_count;++i)
109                         {
110                             if(fileds[i]==-1)
111                             {
112                                 fileds[i]=newsock;//add newsock fd
113                                 break;
114                             }
115                         }
116                         if(i==fds_count)//sum fd effective is full
117                         {
118                             close(newsock);
119                         }
120                         //break;
121                     }else if(fileds[i]>0 &&FD_ISSET(fileds[i],&_reads))
122                     {
123                         char buf[1024];
124                         ssize_t _size=read(fileds[i],buf,sizeof(buf)-1);
124                         ssize_t _size=read(fileds[i],buf,sizeof(buf)-1);
125                         if(_size>0)
126                         {
127                             buf[_size]='\0';
128                             printf("client#%s",buf);
129                             write(fileds[i],buf,_size);
130                         }else if(_size==0)//client close
131                         {
132                             printf("client is closed...\n");
133                             close(fileds[i]);
134                             fileds[i]=-1;//set -1,
135                         }
136                     }
137                 }
138             }
139             break;
140    
141         }
142     }
143     return 0;
144 }


客戶端:


 

1 #include<stdio.h>
  2 #include<string.h>
  3 #include<errno.h>
  4 #include<stdlib.h>
  5 #include<netinet/in.h>
  6 #include<unistd.h>
  7 #include<arpa/inet.h>
  8 
  9 void Usage(const char*proc)
 10 {
 11     printf("Usage:%s [remoteip] [remoteport]\n",proc);
 12 }
 13 
 14 int main(int argc,char* argv[])
 15 {
 16     if(argc!=3)
 17      {
 18          Usage(argv[0]);
 19          exit(1);
 20      }
 21 
 22      int _port=atoi(argv[2]);
 23      char *_ip=argv[1];
 1 #include<stdio.h>
  2 #include<string.h>
  3 #include<errno.h>
  4 #include<stdlib.h>
  5 #include<netinet/in.h>
  6 #include<unistd.h>
  7 #include<arpa/inet.h>
  8 
  9 void Usage(const char*proc)
 10 {
 11     printf("Usage:%s [remoteip] [remoteport]\n",proc);
 12 }
 13 
 14 int main(int argc,char* argv[])
 15 {
 16     if(argc!=3)
 17      {
 18          Usage(argv[0]);
 19          exit(1);
 20      }
 21 
 22      int _port=atoi(argv[2]);
 23      char *_ip=argv[1];
 24      int sock=socket(AF_INET,SOCK_STREAM,0);
 25      if(sock<0)
 26      {
 27          perror("socket");
 28          exit(2);
 29      }
 30      struct sockaddr_in remote;
 31      remote.sin_family=AF_INET;
 32      remote.sin_port=htons(_port);
 33      remote.sin_addr.s_addr=inet_addr(_ip);
 34      int ret=connect(sock,(struct sockaddr*)&remote,sizeof(remote));
 35      if(ret<0)
 36      {
 37          perror("connect");
 38          exit(3);
 39      }
 40      char buf[1024];
 41      while(1)
 42      {
 43          memset(buf,'\0',sizeof(buf));
 44          printf("please input:");
 45          fflush(stdout);
 46          if(read(0,buf,sizeof(buf)-1)>0)
 47          {
 48              write(sock,buf,strlen(buf));
 49          }
 50    
 51          ssize_t _size=read(sock,buf,sizeof(buf)-1);
 52          if(_size>0)
 53          {
 54              printf("server----client:%s",buf);
 55          }
 56    
 57      }
 58      return 0;
 59 }


結(jié)果回顯:

用select實(shí)現(xiàn)IO的復(fù)用

使用select實(shí)現(xiàn)多路復(fù)用同時(shí)也存在弊端:

每次調(diào)用select,都需要把fd集合從用戶態(tài)拷貝到內(nèi)核態(tài),需要在內(nèi)核中遍歷傳遞進(jìn)的所有文件描述符,當(dāng)fd很多時(shí)導(dǎo)致開(kāi)銷大 

 

 


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI