select of I/O Multiplexing in Linux Communication Mechanisms

select function functions:

The system provides select function to realize multiplexing input/output model. Select system calls are used to allow our program to monitor the state changes of multiple file handles. The program stops at select and waits until one or more of the monitored file handles have changed state. As far as file handles are concerned, they are actually integers. The most familiar handles are 0, 1 and 2. 0 is standard input, 1 is standard output, and 2 is standard error output. 0, 1 and 2 are integers, and the corresponding FILE* structures are stdin, stdout and stderr.

Function prototype:

  1. int select(int maxfd,fd_set *rdset,fd_set *wrset, \  
  2.            fd_set *exset,struct timeval *timeout);  

Description of parameters:

The parameter maxfd is the maximum file descriptor value to be monitored + 1; rdset, wrset and exset correspond to the set of readable file descriptors, the set of writable file descriptors and the set of exception file descriptors respectively. The struct timeval structure is used to describe the length of a period of time. If no event occurs in the descriptor that needs to be monitored, the function returns with a return value of 0.

The following macros provide a way to handle these three descriptive phrases:
FD_CLR(inr fd,fd_set* set); used to clear the position of related FD in the set of descriptive phrases
FD_ISSET (int fd, fd_set*set); used for test Relevant fd in descriptive phrase set Is the Bit True
FD_SET (int fd,fd_set*set); used to set the bits of the relevant FD in the description phrase set
FD_ZERO (fd_set*set); used to remove all parts of the descriptive phrase set

The parameter timeout is the structure timeval, which is used to set the waiting time of select(). Its structure is defined as follows:

  1. struct timeval  
  2. {  
  3.     time_t tv_sec;//second  
  4.     time_t tv_usec;//minisecond  
  5. }; 

  6. Function return value:

Returns the number of changes in the state of the file descriptor when the execution is successful

If return 0 means that the time out time has exceeded before the state of the descriptor has changed, no return is made.

When an error occurs, it returns - 1. The cause of the error lies in errno. At this time, the parameters readfds, writefds, exceptfds and

The value of timeout becomes unpredictable. The error value may be:

EBADF file descriptor is invalid or the file is closed

EINTR This modulation is interrupted by the signal.

EINVAL parameter n is negative.

ENOMEM Core Memory Insufficient


The characteristics of select model:
1) The number of monitorable file descriptors depends on the value of sizeof(fd_set). sizeof(fd_set) = 512 on my server. Each bit table shows a file descriptor. The maximum file descriptor supported on my server is 512*8 = 4096.   2) When adding fd to select monitor set, we need to use one more data structure array saves fd in the select monitor set, one for re-selection After returning, array is used as source data and fd_set for FD_ISSET judgment. Secondly, after the return of select, the FD added before but without incident will be emptied. Then, before each start of select, the FD will be added one by one from array (FD_ZERO is the first), while scanning array, the maxfd of FD will be obtained, which is the first parameter of select.   3) The select model must loop array before select (add fd, take maxfd), and select returns to loop array after select (FD_ISSET judges whether time has occurred).
select shortcomings:
(1) Each call to select requires copying the FD set from the user state to the kernel state, which costs a lot in fd. (2) At the same time, every call to select needs to traverse all the FDS passed in by the kernel, which costs a lot in many fd s.

(3) The number of file descriptors supported by select is too small. The default is 1024.

//select_server.c
//This example takes reading as an example:

  1 #include<stdio.h>                                                           
  2 #include<sys/types.h>
  3 #include<stdlib.h>
  4 #include<string.h>
  5 #include<sys/socket.h>
  6 #include<netinet/in.h>
  7 #include<arpa/inet.h>
  8 #include<fcntl.h>
  9 #include<unistd.h>
 10 #include<sys/select.h>
 11 
 12 int fds[1024];
 13 
 14 static void  usage(const char *proc)
 15 {
 16    printf("Usage: %s [local_ip][local_port]\n", proc);
 17 }
 18 
 19 int startup(const char* _ip , int _port)
 20 {
 21   int sock = socket(AF_INET , SOCK_STREAM , 0);
 22   if(sock < 0)
 23   {
 24       perror("socket");
 25       exit(2);
 26   }
 27   struct sockaddr_in local;
 28   local.sin_family = AF_INET;
 29   local.sin_port =htons(_port);
 30   local.sin_addr.s_addr =inet_addr(_ip);
 31 
 32   if(bind(sock , (struct sockaddr*)&local , sizeof(local)) < 0)
 33   {
 34       perror("bind");
 35       exit(3);
 36   }
 37   if(listen(sock , 10) < 0)
 38   {
 39       perror("listen");
 40       exit(4);
 41   }
 42   return sock;
 43 }
 44 int main(int argc , char *argv[])
 45 {
 46   if(argc != 3)   
 47   {
 48     usage(argv[0]);
 49     return 1;
 50   }
 51   int listen_sock = startup(argv[1] , atoi(argv[2]));
 52   int nums = sizeof(fds) / sizeof(fds[0]);
 53   int maxfd = -1;
 54   int i = 1;
 55   for( ; i < nums ; i++)
 56   {
 57       fds[i] = -1;
 58   }
 59   fds[0] = listen_sock;
 60   while(1)
 61   {
 62    struct timeval timeout = {5 , 0};
 63    fd_set rfds;//Create a set of read file descriptors
 64    FD_ZERO( &rfds); 
 65    maxfd = -1;
 66    for(i=0 ; i<nums ; i++ )
 67    {
 68        if(fds[i] > 0)
 69        {
 70            FD_SET(fds[i] , &rfds);
 71            if(maxfd < fds[i])
 72            {
 73                maxfd = fds[i];
 74            }
 75        }
 76    }
 77   switch(select(maxfd+1 , &rfds , NULL , NULL ,&timeout))
 78   {
 79       case 0:   printf("timeout....!\n");  break;
 80       case -1:  perror("select"); break;
 81       default://at last one fd ready!
 82         {
 83             for(i=0 ; i<nums ;i++)
 84             {
 85                 if(fds[i] < 0)  
 86                 {
 87                     continue;
 88                 }
 89                 if (i==0 && FD_ISSET(listen_sock , &rfds))
 90                 {
 91                     //listen_sock ready
 92                     struct sockaddr_in client;
 93                     socklen_t len=sizeof(client);
 94                     int new_sock = accept(listen_sock,\
 95                                 (struct sockaddr*)&client , &len );
 96                     if(new_sock < 0)
 97                     {
 98                         perror("accept");
 99                         continue;
100                     }
101                     printf("get new client: [%s:%d]",\
102                                 inet_ntoa(client.sin_addr),\
103                                 ntohs(client.sin_port));
104                     int j = 1;
105                     for( ; j<nums ; j++)
106                     {             
107                         if(fds[j] == -1)
108                         {
109                             break;
110                         }
111                     }
112                     if(j == nums)
113                     {
114                         printf("server full!\n");
115                         close(new_sock);
116                     }
117                     else
118                     {
119                         fds[j] = new_sock;
120                     }
121                 }
122                 else if(i > 0 && FD_ISSET(fds[i] , &rfds))
123                 {
124                     //other fd ready
125                     char buf[1024];
126                     ssize_t s = read(fds[i], buf ,sizeof(buf)-1);
127                     if(s > 0)          
128                     {
129                         buf[s] = 0;
130                         printf("client say# %s\n",buf);
131                     }
132                     else if(s == 0)
133                     {
134                         printf("client quit!\n");
135                         close(fds[i]);
136                         fds[i] = -1;
137                     }
138                     else
139                     {
140                         perror("read");
141                     }
142                 }
143                 else
144                 {}
145             }
146         }
147         break;
148     }
149   }
150   return 0;
151 }   


Keywords: socket

Added by mauri_gato on Sun, 09 Jun 2019 01:24:35 +0300