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:
- int select(int maxfd,fd_set *rdset,fd_set *wrset, \
- 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:
- struct timeval
- {
- time_t tv_sec;//second
- time_t tv_usec;//minisecond
- };
-
- 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
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 }