Code:
#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 <signal.h>
#define PORT 9034 // port we're listening on
#define MAX_QUEUE_LEN 3
int main(int argc, char *argv[])
{
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
struct sockaddr_in myaddr; // server address
struct sockaddr_in remoteaddr; // client address
int fdmax; // maximum file descriptor number
int listener; // listening socket descriptor
int newfd; // newly accept()ed socket descriptor
char buf[256]; // buffer for client data
char outbuf[256];
int nbytes;
int yes=1; // for setsockopt() SO_REUSEADDR, below
socklen_t addrlen;
int i, j;
int nclients=0;
struct info {
struct sockaddr_in in;
int fd;
} q_list[MAX_QUEUE_LEN];
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
// get the listener
if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
// lose the pesky "address already in use" error message
if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
// bind
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = INADDR_ANY;
myaddr.sin_port = htons(PORT);
memset(myaddr.sin_zero, '\0', sizeof myaddr.sin_zero);
if (bind(listener, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1) {
perror("bind");
exit(1);
}
// listen
if (listen(listener, 10) == -1) {
perror("listen");
exit(1);
}
// add the listener to the master set
FD_SET(listener, &master);
// keep track of the biggest file descriptor
fdmax = listener; // so far, it's this one
// main loop
for(;;) {
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(1);
}
// run through the existing connections looking for data to read
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { // we got one!!
if (i == listener) {
// handle new connections
addrlen = sizeof(remoteaddr);
if ((newfd = accept(listener, (struct sockaddr *)&remoteaddr,
&addrlen)) == -1) {
perror("accept"); } else {
if (nclients>=MAX_QUEUE_LEN) {
sprintf(outbuf,"Queue full (%d connections).\n", nclients);
if (send(newfd, outbuf, strlen(outbuf), 0) == -1) {
perror("send");
}
close(newfd); // bye!
continue;
}
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) { // keep track of the maximum
fdmax = newfd;
}
printf("selectserver: new connection from %s on "
"socket %d\n", inet_ntoa(remoteaddr.sin_addr), newfd);
q_list[nclients].in=remoteaddr;
q_list[nclients].fd=newfd;
nclients++;
printf("now we have %d clients on queue.\n", nclients);
}
} else { //if data is not from server (listener socket)
// handle data from a client
if ((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
// connection closed
printf("selectserver: socket %d hung up\n", i);
} else {
perror("recv");
}
close(i); // bye!
FD_CLR(i, &master); // remove from master set
for(j=0; j<nclients; j++) if (q_list[j].fd == i) break;
nclients--;
for(; j<nclients; j++)
q_list[j]=q_list[j+1];
printf("now we have %d clients on queue.\n", nclients);
} else { // we got some data from a client
if(i == q_list[0].fd)
printf("Received = %c\n",buf[0]);
else {
strcpy(outbuf,"Sorry, you can't send commands. Wait for your turn.\n");
if (send(i, outbuf, strlen(outbuf), 0) == -1) {
perror("send");
}
}
if(buf[0]=='l') {
strcpy(buf,"List of connected clients:\n");
if (send(i, buf, strlen(buf), 0) == -1) {
perror("send");
}
for(j = 0; j < nclients; j++) {
//if (FD_ISSET(j, &master) && j!= listener) {
sprintf(buf,"Client %d: IP %s on socket %d\n", j+1, inet_ntoa(q_list[j].in.sin_addr), q_list[j].fd );
if (send(i, buf, strlen(buf), 0) == -1) {
perror("send");
}
}
sprintf(buf,"End of client list.\n");
if (send(i, buf, strlen(buf), 0) == -1) {
perror("send");
}
}
}
}
}
}
}
return 0;
}