标签:
This sample program illustrates a server application that uses nonblocking and the select() API.
The following calls are used in the example:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/ioctl.h> 4 #include <sys/socket.h> 5 #include <sys/time.h> 6 #include <netinet/in.h> 7 #include <errno.h> 8 9 #define SERVER_PORT 12345 10 11 #define TRUE 1 12 #define FALSE 0 13 14 main (int argc, char *argv[]) 15 { 16 int i, len, rc, on = 1; 17 int listen_sd, max_sd, new_sd; 18 int desc_ready, end_server = FALSE; 19 int close_conn; 20 char buffer[80]; 21 struct sockaddr_in6 addr; 22 struct timeval timeout; 23 struct fd_set master_set, working_set; 24 25 /*************************************************************/ 26 /* Create an AF_INET6 stream socket to receive incoming */ 27 /* connections on */ 28 /*************************************************************/ 29 listen_sd = socket(AF_INET6, SOCK_STREAM, 0); 30 if (listen_sd < 0) 31 { 32 perror("socket() failed"); 33 exit(-1); 34 } 35 36 /*************************************************************/ 37 /* Allow socket descriptor to be reuseable */ 38 /*************************************************************/ 39 rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, 40 (char *)&on, sizeof(on)); 41 if (rc < 0) 42 { 43 perror("setsockopt() failed"); 44 close(listen_sd); 45 exit(-1); 46 } 47 48 /*************************************************************/ 49 /* Set socket to be nonblocking. All of the sockets for */ 50 /* the incoming connections will also be nonblocking since */ 51 /* they will inherit that state from the listening socket. */ 52 /*************************************************************/ 53 rc = ioctl(listen_sd, FIONBIO, (char *)&on); 54 if (rc < 0) 55 { 56 perror("ioctl() failed"); 57 close(listen_sd); 58 exit(-1); 59 } 60 61 /*************************************************************/ 62 /* Bind the socket */ 63 /*************************************************************/ 64 memset(&addr, 0, sizeof(addr)); 65 addr.sin6_family = AF_INET6; 66 memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any)); 67 addr.sin6_port = htons(SERVER_PORT); 68 rc = bind(listen_sd, 69 (struct sockaddr *)&addr, sizeof(addr)); 70 if (rc < 0) 71 { 72 perror("bind() failed"); 73 close(listen_sd); 74 exit(-1); 75 } 76 77 /*************************************************************/ 78 /* Set the listen back log */ 79 /*************************************************************/ 80 rc = listen(listen_sd, 32); 81 if (rc < 0) 82 { 83 perror("listen() failed"); 84 close(listen_sd); 85 exit(-1); 86 } 87 88 /*************************************************************/ 89 /* Initialize the master fd_set */ 90 /*************************************************************/ 91 FD_ZERO(&master_set); 92 max_sd = listen_sd; 93 FD_SET(listen_sd, &master_set); 94 95 /*************************************************************/ 96 /* Initialize the timeval struct to 3 minutes. If no */ 97 /* activity after 3 minutes this program will end. */ 98 /*************************************************************/ 99 timeout.tv_sec = 3 * 60; 100 timeout.tv_usec = 0; 101 102 /*************************************************************/ 103 /* Loop waiting for incoming connects or for incoming data */ 104 /* on any of the connected sockets. */ 105 /*************************************************************/ 106 do 107 { 108 /**********************************************************/ 109 /* Copy the master fd_set over to the working fd_set. */ 110 /**********************************************************/ 111 memcpy(&working_set, &master_set, sizeof(master_set)); 112 113 /**********************************************************/ 114 /* Call select() and wait 3 minutes for it to complete. */ 115 /**********************************************************/ 116 printf("Waiting on select()...\n"); 117 rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout); 118 119 /**********************************************************/ 120 /* Check to see if the select call failed. */ 121 /**********************************************************/ 122 if (rc < 0) 123 { 124 perror(" select() failed"); 125 break; 126 } 127 128 /**********************************************************/ 129 /* Check to see if the 3 minute time out expired. */ 130 /**********************************************************/ 131 if (rc == 0) 132 { 133 printf(" select() timed out. End program.\n"); 134 break; 135 } 136 137 /**********************************************************/ 138 /* One or more descriptors are readable. Need to */ 139 /* determine which ones they are. */ 140 /**********************************************************/ 141 desc_ready = rc; 142 for (i=0; i <= max_sd && desc_ready > 0; ++i) 143 { 144 /*******************************************************/ 145 /* Check to see if this descriptor is ready */ 146 /*******************************************************/ 147 if (FD_ISSET(i, &working_set)) 148 { 149 /****************************************************/ 150 /* A descriptor was found that was readable - one */ 151 /* less has to be looked for. This is being done */ 152 /* so that we can stop looking at the working set */ 153 /* once we have found all of the descriptors that */ 154 /* were ready. */ 155 /****************************************************/ 156 desc_ready -= 1; 157 158 /****************************************************/ 159 /* Check to see if this is the listening socket */ 160 /****************************************************/ 161 if (i == listen_sd) 162 { 163 printf(" Listening socket is readable\n"); 164 /*************************************************/ 165 /* Accept all incoming connections that are */ 166 /* queued up on the listening socket before we */ 167 /* loop back and call select again. */ 168 /*************************************************/ 169 do 170 { 171 /**********************************************/ 172 /* Accept each incoming connection. If */ 173 /* accept fails with EWOULDBLOCK, then we */ 174 /* have accepted all of them. Any other */ 175 /* failure on accept will cause us to end the */ 176 /* server. */ 177 /**********************************************/ 178 new_sd = accept(listen_sd, NULL, NULL); 179 if (new_sd < 0) 180 { 181 if (errno != EWOULDBLOCK) 182 { 183 perror(" accept() failed"); 184 end_server = TRUE; 185 } 186 break; 187 } 188 189 /**********************************************/ 190 /* Add the new incoming connection to the */ 191 /* master read set */ 192 /**********************************************/ 193 printf(" New incoming connection - %d\n", new_sd); 194 FD_SET(new_sd, &master_set); 195 if (new_sd > max_sd) 196 max_sd = new_sd; 197 198 /**********************************************/ 199 /* Loop back up and accept another incoming */ 200 /* connection */ 201 /**********************************************/ 202 } while (new_sd != -1); 203 } 204 205 /****************************************************/ 206 /* This is not the listening socket, therefore an */ 207 /* existing connection must be readable */ 208 /****************************************************/ 209 else 210 { 211 printf(" Descriptor %d is readable\n", i); 212 close_conn = FALSE; 213 /*************************************************/ 214 /* Receive all incoming data on this socket */ 215 /* before we loop back and call select again. */ 216 /*************************************************/ 217 do 218 { 219 /**********************************************/ 220 /* Receive data on this connection until the */ 221 /* recv fails with EWOULDBLOCK. If any other */ 222 /* failure occurs, we will close the */ 223 /* connection. */ 224 /**********************************************/ 225 rc = recv(i, buffer, sizeof(buffer), 0); 226 if (rc < 0) 227 { 228 if (errno != EWOULDBLOCK) 229 { 230 perror(" recv() failed"); 231 close_conn = TRUE; 232 } 233 break; 234 } 235 236 /**********************************************/ 237 /* Check to see if the connection has been */ 238 /* closed by the client */ 239 /**********************************************/ 240 if (rc == 0) 241 { 242 printf(" Connection closed\n"); 243 close_conn = TRUE; 244 break; 245 } 246 247 /**********************************************/ 248 /* Data was received */ 249 /**********************************************/ 250 len = rc; 251 printf(" %d bytes received\n", len); 252 253 /**********************************************/ 254 /* Echo the data back to the client */ 255 /**********************************************/ 256 rc = send(i, buffer, len, 0); 257 if (rc < 0) 258 { 259 perror(" send() failed"); 260 close_conn = TRUE; 261 break; 262 } 263 264 } while (TRUE); 265 266 /*************************************************/ 267 /* If the close_conn flag was turned on, we need */ 268 /* to clean up this active connection. This */ 269 /* clean up process includes removing the */ 270 /* descriptor from the master set and */ 271 /* determining the new maximum descriptor value */ 272 /* based on the bits that are still turned on in */ 273 /* the master set. */ 274 /*************************************************/ 275 if (close_conn) 276 { 277 close(i); 278 FD_CLR(i, &master_set); 279 if (i == max_sd) 280 { 281 while (FD_ISSET(max_sd, &master_set) == FALSE) 282 max_sd -= 1; 283 } 284 } 285 } /* End of existing connection is readable */ 286 } /* End of if (FD_ISSET(i, &working_set)) */ 287 } /* End of loop through selectable descriptors */ 288 289 } while (end_server == FALSE); 290 291 /*************************************************************/ 292 /* Clean up all of the sockets that are open */ 293 /*************************************************************/ 294 for (i=0; i <= max_sd; ++i) 295 { 296 if (FD_ISSET(i, &master_set)) 297 close(i); 298 } 299 }
标签:
原文地址:http://www.cnblogs.com/kiss007/p/4284295.html