/*
* select_socket.c
* This program demonstrates how to use the select function.
* Note that although we did not cover sockets in this book,
* the code will remain the same for file descriptors. To use
* this program. Open several xterms, run the program, and then
* telnet to any of the ports. Once the telnet session is connected
* type anything and it will echo back. For example:
*
* From xterm 1:
*
* bash$ ./select_socket
*
* From xterm 2:
*
* bash$ telnet localhost 8888
*
* From xterm 3:
*
* bash$ telnet localhost 8889
*
* to compile: gcc -O -pipe select_socket.c -o select_socket
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/time.h>
/* our defines */
#define PORT (8888)
#define MAXBUFF (1024)
#define MAX_CONN (16)
#define TIMEOUT (1024)
#define MY_MAX(a,b) (a = (a > b) ? a : b )
#define SELECT_ERR (-1)
#define SELECT_EXPIRE (0)
int main(int argc, char **argv)
{
int i, j, max = 0, sfds[MAX_CONN], afd;
size_t len;
fd_set list;
char buff[MAXBUFF];
struct sockaddr_in sock[MAX_CONN];
struct timeval tm;
/* initialize our buffer */
memset(buff, 0, MAXBUFF);
/*
* We will loop through each file descriptor. First
* we will create a socket bind to it and then call
* listen on it. If we get an error we just exit,
* which is fine for demo code, but not good in the
* real world where errors should be handled properly.
*/
for( i = 0; i < MAX_CONN; i++ )
{
/* check to see that we can create them */
if( (sfds[i] = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("Cannot create socket");
exit(1);
}
/* now fill out our socket stuctures */
memset(&sock[i], 0, sizeof(struct sockaddr_in));
sock[i].sin_family = AF_INET;
sock[i].sin_port = htons(PORT + i);
len = INADDR_ANY;
memset(&sock[i].sin_addr, len, sizeof(struct in_addr));
/* Now bind to the socket */
if( bind(sfds[i], (struct sockaddr *) &sock[i], sizeof(struct sockaddr_in)) < 0 )
{
perror("Cannot bind to the socket");
exit(1);
}
/* set our options */
if( setsockopt(sfds[i], SOL_SOCKET, SO_REUSEADDR, &j, sizeof(int)) < 0 )
{
perror("Cannot set socket options \n");
}
/* set the socket into the listen state */
if( listen(sfds[i], 5) < 0 )
{
perror("Failed to listen on the socket \n");
}
}/* for */
/* Create our timeout structure */
tm.tv_sec = TIMEOUT;
tm.tv_usec = 0;
/*
* Our main loop. Note that we will have to re-initialize
* and re-add the descriptors to the fd_set structure
* each time we loop around. This is because select will
* modify values inside the fd_set structure. Therefore,
* the fd_set structure is no longer the same structure as
* when we first passed it to select.
*/
while( 1 )
{
max = 0;
/* Always clear the fd_set structure before using it ! */
FD_ZERO(&list);
for( i =0; i < MAX_CONN; i++ )
{
FD_SET(sfds[i], &list);
max = MY_MAX(max, sfds[i] );
}
max++;
/*
* Now call select. Note, when select returns we have three possibilities:
* I) The timeout has expired
* II) Select had an error
* III) We have a socket ready to accept
*/
j = select(max, &list, NULL, NULL, &tm);
switch( j )
{
case SELECT_EXPIRE:
printf("Timeout has expired !\n");
break;
case SELECT_ERR:
perror("Error on select");
default:
/*
* Now we have to loop through each descriptors to
* see which is ready to accept. To do this we must
* use the FD_ISSET macro.
*/
for( i =0; i < MAX_CONN; i++ )
{
if( FD_ISSET(sfds[i], &list) )
{
/*
* We now have to accept the connection and then
* echo back what is written.
*/
printf("We have a connection \n");
len = sizeof(struct sockaddr_in);
afd = accept(sfds[i], (struct sockaddr *)&sock[i], &len);
len = read(afd, buff, MAXBUFF);
write(afd, buff, len +1);
printf("Echoing back:\n %s \n", buff);
close(afd);
}
} /* for */
} /* switch */
}/* while(1) */
/* FIN */
return(0);
} /* main */
syntax highlighted by Code2HTML, v. 0.9