Code:
/* This is a server. This code allows multiple client
to connect with the same server's port.
Non-Blocking I/O and select();
Step 1: Setup Address structure
Step 2: Create a socket
Step 3: Bind the socket to the port
Step 4: Listen to the socket
Step 5: Setup an infinite loop to make connections
IBM
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/
index.jsp?topic=%2Frzab6%2Frzab6xnonblock.htm
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MAX_CLIENTS 20
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
fd_set master; //file descriptor master list
fd_set read_fds; //file descriptor temp list for select()
int fdmax; //file descriptor maximum number
int sockfd, newsockfd, portno;//socket, accept, port number
socklen_t clilen;
char buffer[256];//for recv and send of data
int yes=1; //for setsockopt
struct sockaddr_in serv_addr, cli_addr;
struct client{ //struct used to store client information
char name[32]; //contains the client name
int fd; //contains the client file descriptor
};
struct client database[MAX_CLIENTS]; //database of client information
memset(&database, 0, sizeof database);
int numClients = 0; //keep track of how many clients are connected
int i, j; //loop counters
int nbytes; //data recv from the client
char remoteIP[INET6_ADDRSTRLEN + 1];
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
//Check if port is given
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
//Step 1: Setup Address structure
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
//Step 2: Create a socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0){
error("ERROR opening socket");
}
printf("The sockfd1 value is: %d\n", sockfd);
//reuse port if it was still in use
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,
&yes,sizeof(int)) == -1) {
error("setsockopt");
exit(1);
}
//Step 3: Bind the socket to the port
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0){
close(sockfd);
}
//Step 4:Listen to the socket
if (listen(sockfd,10) == -1){
error("ERROR on listen");
exit(3);
}
//add file descriptor to master set list
FD_SET(sockfd, &master);
fdmax = sockfd; //as of now, the biggest fd is listener
printf("The fdmax value is: %d\n", fdmax);
printf("Waiting for Client connections...\n");
usleep(1000);
//main while loop: LOOP and check for connection requests, recieved messages
while(1) {
read_fds = master; //copy master list to temp list
//Check to see if the select call failed.
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
//printf("We are at before the main for loop");
printf("The sockfd2 value is: %d\n", sockfd);
//Step 5: Setup an infinite loop to make connections
for(i = 0; i <= fdmax; i++) {
//Check to see if this descriptor is ready
if (FD_ISSET(i, &read_fds)) { //Check if FD is set
//Check to see if this is the listening socket
if (i == sockfd) {//the fd is the listener port [a client is attempting to connect()]
//handle new connections
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
printf("The newsockfd value is: %d\n", newsockfd);
if (newsockfd < 0)
error("ERROR on accept");
else {//accept successful
//Add the new incoming connection to the master read set
FD_SET(newsockfd, &master); //add fd to master list
if (newsockfd > fdmax) { //keep tracks of the FD max
fdmax = newsockfd;
database[numClients].fd = newsockfd; //add connection to array
numClients++; //increment # of client connections
printf("New Connection Accepted - Total Connections: %d\n", numClients);
}
printf("selectserver: new connection from %s on "
"socket %d\n",
inet_ntop(AF_INET, &(cli_addr.sin_addr),
remoteIP, sizeof(remoteIP)),
newsockfd);
}
} else {//not from listener port, must be data from client
// handle data from a client
printf(" Descriptor %d is readable\n", i);
if ((nbytes = recv(i, buffer, sizeof buffer, 0)) <= 0) {
//Checks if any client(s) closed
if (nbytes == 0) {//conection closed
printf("Alert: socket %d hung up\n", i);
} else {
error("recv");
}
close(i); //close sockfd that leaves!
FD_CLR(i, &master); //remove that client from master set
} else {
//we got some data from a client
for(j = 0; j <= fdmax; j++) {
//send to data every client
if (FD_ISSET(j, &master)) {
//except the client that sent the data
if (j != sockfd && j != i) {
if (send(j, buffer, nbytes, 0) == -1) {
error("send");
}
}
}
}
}
} // End handle data from client
} // End got new incoming connection
} // End flag set by a file descriptors
} // End of main while Loop
return 0;
}//End of main