poll()例程(包含 bind,listen,accept,setsockopt 的用法)
Using
The
The
Socket flow of events: Server that uses 0Indicates that the process times out. In this example, the timeout is set for 3 minutes (in milliseconds). -1 Indicates that the process has failed. 1 Indicates only one descriptor is ready to be processed, which is processed only if it is the listening socket. 1++ Indicates that multiple descriptors are waiting to be processed. The poll() API allows simultaneous connection with all descriptors in the queue on the listening socket.The #include<stdio.h>#include<stdlib.h>#include<sys/ioctl.h>#include<sys/poll.h>#include<sys/socket.h>#include<sys/time.h>#include<netinet/in.h>#include<errno.h>#defineSERVER_PORT12345#defineTRUE1#defineFALSE0/** * There are 2 kind of sockets, one is the only listening socket, the other is the accepted sockets. * For the listening socket, poll() returns when a connection comes; for those accepted sockets, poll() returns when * data coming form the client is readable. */intmain (int argc, char *argv[]){intlen, rc, on = 1;intlisten_sd = -1, new_sd = -1;intdesc_ready, end_server = FALSE, compress_array = FALSE;intclose_conn;charbuffer[80];struct sockaddr_inaddr;inttimeout;struct pollfdfds[200];intnfds = 1, current_size = 0, i, j;/*************************************************************//* Create an AF_INET stream socket to receive incoming *//* connections on *//*************************************************************/listen_sd = socket(AF_INET, SOCK_STREAM, 0);if (listen_sd < 0){perror("socket() failed");exit(-1);}/*************************************************************//* Allow socket descriptor to be reuseable *//*************************************************************/rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR,(char *)&on, sizeof(on));if (rc < 0){perror("setsockopt() failed");close(listen_sd);exit(-1);}/*************************************************************//* Set socket to be nonblocking. All of the sockets for *//* the incoming connections will also be nonblocking since *//* they will inherit that state from the listening socket. *//*************************************************************/rc = ioctl(listen_sd, FIONBIO, (char *)&on);if (rc < 0){perror("ioctl() failed");close(listen_sd);exit(-1);}/*************************************************************//* Bind the socket *//*************************************************************/memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_addr.s_addr = htonl(INADDR_ANY);addr.sin_port = htons(SERVER_PORT);rc = bind(listen_sd,(struct sockaddr *)&addr, sizeof(addr));if (rc < 0){perror("bind() failed");close(listen_sd);exit(-1);}/*************************************************************//* Set the listen back log *//*************************************************************/rc = listen(listen_sd, 32);if (rc < 0){perror("listen() failed");close(listen_sd);exit(-1);}/*************************************************************//* Initialize the pollfd structure *//*************************************************************/memset(fds, 0 , sizeof(fds));/*************************************************************//* Set up the initial listening socket *//*************************************************************/fds[0].fd = listen_sd;fds[0].events = POLLIN;/*************************************************************//* Initialize the timeout to 3 minutes. If no *//* activity after 3 minutes this program will end. *//* timeout value is based on milliseconds. *//*************************************************************/timeout = (3 * 60 * 1000);/*************************************************************//* Loop waiting for incoming connects or for incoming data *//* on any of the connected sockets. *//*************************************************************/do{/***********************************************************//* Call poll() and wait 3 minutes for it to complete. *//***********************************************************/printf("Waiting on poll()...\n");rc = poll(fds, nfds, timeout);/***********************************************************//* Check to see if the poll call failed. *//***********************************************************/if (rc < 0){perror(" poll() failed");break;}/***********************************************************//* Check to see if the 3 minute time out expired. *//***********************************************************/if (rc == 0){printf(" poll() timed out. End program.\n");break;}/***********************************************************//* One or more descriptors are readable. Need to *//* determine which ones they are. *//***********************************************************/current_size = nfds;for (i = 0; i < current_size; i++){/*********************************************************//* Loop through to find the descriptors that returned *//* POLLIN and determine whether it's the listening *//* or the active connection. *//*********************************************************/if(fds[i].revents == 0)continue;/*********************************************************//* If revents is not POLLIN, it's an unexpected result, *//* log and end the server. *//*********************************************************/if(fds[i].revents != POLLIN){printf(" Error! revents = %d\n", fds[i].revents);end_server = TRUE;break;}/*******************************************************//* Listening descriptor is readable. *//*******************************************************/if (fds[i].fd == listen_sd){printf(" Listening socket is readable\n");/*******************************************************//* Accept all incoming connections that are *//* queued up on the listening socket before we *//* loop back and call poll again. *//*******************************************************/do{/*****************************************************//* Accept each incoming connection. If *//* accept fails with EWOULDBLOCK, then we *//* have accepted all of them. Any other *//* failure on accept will cause us to end the *//* server. *//*****************************************************/new_sd = accept(listen_sd, NULL, NULL);if (new_sd < 0){/*************************************************//* If the errno is EAGAIN or EWOULDBLOCK, then *//* no pending connections are present on the *//* queue, which indicates we have accept all of *//* them. *//*************************************************/if (errno != EWOULDBLOCK){perror(" accept() failed");end_server = TRUE;}break;}/*****************************************************//* Add the new incoming connection to the *//* pollfd structure *//*****************************************************/printf(" New incoming connection - %d\n", new_sd);fds[nfds].fd = new_sd;fds[nfds].events = POLLIN;nfds++;/*****************************************************//* Loop back up and accept another incoming *//* connection *//*****************************************************/} while (new_sd != -1);}/*********************************************************//* This is not the listening socket, therefore an *//* existing connection must be readable *//*********************************************************/else{printf(" Descriptor %d is readable\n", fds[i].fd);close_conn = FALSE;/*******************************************************//* Receive all incoming data on this socket *//* before we loop back and call poll again. *//*******************************************************/do{/*****************************************************//* Receive data on this connection until the *//* recv fails with EWOULDBLOCK. If any other *//* failure occurs, we will close the *//* connection. *//*****************************************************/rc = recv(fds[i].fd, buffer, sizeof(buffer), 0);if (rc < 0){if (errno != EWOULDBLOCK){perror(" recv() failed");close_conn = TRUE;}break;}/*****************************************************//* Check to see if the connection has been *//* closed by the client *//*****************************************************/if (rc == 0){printf(" Connection closed\n");close_conn = TRUE;break;}/*****************************************************//* Data was received *//*****************************************************/len = rc;printf(" %d bytes received\n", len);/*****************************************************//* Echo the data back to the client *//*****************************************************/rc = send(fds[i].fd, buffer, len, 0);if (rc < 0){perror(" send() failed");close_conn = TRUE;break;}} while(TRUE);/*******************************************************//* If the close_conn flag was turned on, we need *//* to clean up this active connection. This *//* clean up process includes removing the *//* descriptor. *//*******************************************************/if (close_conn){close(fds[i].fd);fds[i].fd = -1;compress_array = TRUE;}} /* End of existing connection is readable */} /* End of loop through pollable descriptors *//***********************************************************//* If the compress_array flag was turned on, we need *//* to squeeze together the array and decrement the number *//* of file descriptors. We do not need to move back the *//* events and revents fields because the events will always*//* be POLLIN in this case, and revents is output. *//***********************************************************/if (compress_array){compress_array = FALSE;for (i = 0; i < nfds; i++){if (fds[i].fd == -1){for(j = i; j < nfds; j++){fds[j].fd = fds[j+1].fd;}nfds--;}}}} while (end_server == FALSE); /* End of serving running. *//*************************************************************//* Clean up all of the sockets that are open *//*************************************************************/for (i = 0; i < nfds; i++){if(fds[i].fd >= 0){close(fds[i].fd);}}}
参考资料:http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/rzab6/poll.htm
参考资料:
http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/rzab6/poll.htm