i/o多路转接 select(一)

时间:2022-12-26 15:08:08

select 模型特点
1.可监控的文件描述符个数取决与文件描述符集的大小(sizeof(fd_set) 的值)。假设:sizeof ( fd_set) = 512, 每个bit表示一个文件描述符,则支持的最大文件描述符是512*8=4096.
2.将fd加入select监控集的同时,还要再使用一个数据结构array保存select监控集中的 fd_set,一是用于再select 返回后,array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始 select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个 参数。
3.可见select模型必须在select前循环array(加fd,取maxfd),select返回后循环array(FD_ISSET判断是否有时间发生)。

模型的缺点
1.每次进行select都要把文件描述符集fd由用户态拷贝到内核态,这样的开销会很大。
2 实现select服务器,内部要不断对文件描述符集fd进行循环遍历,当fd很多时,开销也很大。
3.select能监控文件描述符的数量有限,一般为1024。(sizeof(fd_set) * 8 = 1024(fd_set内部是以位图表示文件描述符)

select模型的服务器

  1 #include<stdio.h> 
  2 #include<sys/types.h>
  3 #include<netinet/in.h>
  4 #include<arpa/inet.h>
  5 #include<string.h>
  6 #include<stdlib.h>
  7 #include<time.h>
  8 #include<unistd.h>
  9 
 10 int array_fds[1024];
 11 
 12 int startup(char* ip,int port)
 13 {
 14     int sock = socket(AF_INET,SOCK_STREAM,0);
 15     if(sock<0){
 16         perror("sock");
 17         exit(2);
 18     }
 19     int flg = 1;
 20     setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&flg,sizeof(flg));
 21     struct sockaddr_in local;
 22     local.sin_family = AF_INET;
 23     local.sin_port = htons(port);
 24     local.sin_addr.s_addr = inet_addr(ip);
 25     if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){
 26         perror("bind");
 27         exit(3);
 28     }
 29     if(listen(sock,10)){
 30         perror("listen");
 31         exit(4);
 32     }
 33     return sock;
 34 }
 35 int main(int argc,char*argv[])
 36 {
 37     if(argc!=3){
 38         printf("Usage:%s [local_ip] [local_port]\n",argv[0]);
 39         return 1;
 40     }
 41     int listen_sock = startup(argv[1],atoi(argv[2]));
 42     int maxfds  = 0; //max fd_set 
 43     fd_set rfds;//fd_set
 44     int array_size =  sizeof(array_fds)/sizeof(array_fds[0]);
 45     array_fds[0] = listen_sock;
 46      
 47     //init array_fds
 48     int i = 1;
 49     for(;i<array_size;i++){
 50         array_fds[i] = -1;                                                                      51     }
 52 
 53     while(1)
 54     {
 55         struct timeval timeout = {0,0};
 56         FD_ZERO(&rfds); //empty
 57         maxfds = -1;
 58         i = 0;
 59         for(;i<array_size;i++)
 60         {
 61             if(array_fds[i]>0){
 62                 FD_SET(array_fds[i],&rfds); //put array_fds[i] into rfds
 63                 if(array_fds[i] > maxfds){
 64                     maxfds = array_fds[i];
 65                 }
 66             }
 67         }
 68         switch(select(maxfds+1,&rfds,NULL,NULL,NULL))
 69         {
 70             case 0:
 71                 printf("timeout...\n");
 72                 break;
 73             case -1:
 74                 perror("select");
 75                 break; 
               76             default://success
 77             {
 78                 int j = 0;
 79                 for(;j<array_size;++j)
 80                 {
 81                     if(array_fds[i]<0)
 82                         continue;
 83                     if(j==0&&FD_ISSET(array_fds[j],&rfds))
 84                     {
 85                         struct sockaddr_in client;
 86                         socklen_t len = sizeof(client);
 87                         int new_fd = accept(array_fds[j],(struct sockaddr*)&client,&len);
 88                         if(new_fd < 0){
 89                             perror("accept");
 90                             continue;
 91                         }
 92                         else{
 93                             printf("get a client:%s,%d\n",\
 94                                     inet_ntoa(client.sin_addr),\
 95                                     ntohs(client.sin_port));
 96                             int k = 1;
 97                             for(;k<array_size;k++){
 98                                 if(array_fds[k] <0){
 99                                     array_fds[k] = new_fd;
  101                                 }
102                                 if( k == array_size){
103                                     //no use file
104                                     close(new_fd);
105                                 }
106                             }
107                         }
108                     }
109                     else if(j!=0&&FD_ISSET(array_fds[j],&rfds))
110                     {
111                         char buf[1240];
112                         ssize_t s = read(array_fds[j],\
113                                 buf,sizeof(buf)-1);
114                         if(s > 0){
115                             buf[s]=0;
116                             printf("client say#:%s\n",buf);
117                         }
118                         else if(s==0){
119                             printf("client quit\n");
120                             close(array_fds[j]);
121                             array_fds[j]=-1;
122                         }
123                         else{
124                             perror("read");
125                             close(array_fds[j]);     
   126                         }
127                     }
128                 }
129                 break;
130             }
131         }
132     }
133     return 0;
134 }