A more fully commented version of this server program
/* Author : Ting-jen Yen (yentj@cs.nyu.edu) file name : server.c associated file: client.c Description : This is a simple iterative server that listens at port 1234. It will accept a number (unsigned, integer or float) from the client, and returns twice the number to the client. You can can access this server by running the client program (see file client.c), or just using "telnet" to connect to the server. Usage: Simply type "server" in the host machine to serve at default port 1234. Otherwise type "server -p <port number>". How to compile : On Solaris 2 : % gcc -o server server.c -lsocket On SGI machies : % gcc -o server server.c */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <fcntl.h> #include <string.h> #include <signal.h> int server_sock, con_sock; int srv_port = 1234; struct sockaddr_in source; /* Close all sockets before the forced quit caused by signal */ void signal_handler() { close(con_sock); close(server_sock); exit(0); } /* When the state of a child process is changed, (for example, it is terminated, or ended by call exit(),) the server should call wait() to get the state. This will prevent the child process from becoming a zombie process when it has finished. */ void child_end() { wait(NULL); } void init_servconnection() { struct sockaddr_in server; /* Creating socket */ server_sock = socket(AF_INET, SOCK_STREAM, 0); if (server_sock < 0) { perror("socket"); exit(1); } server.sin_family = AF_INET; server.sin_port = htons(srv_port); server.sin_addr.s_addr = INADDR_ANY; /* bind the specified port to this socket */ if (bind(server_sock, (struct sockaddr *) & server, sizeof(server)) < 0) { perror("bind socket"); exit(1); } /* listen for connection */ if (listen(server_sock, 5) < 0) { perror("listen"); exit(1); } } attenteconnection() { int lg, pid; lg = sizeof(struct sockaddr_in); /* repeat until accept a successful connect */ do con_sock = accept(server_sock, (struct sockaddr *) & source, &lg); while (con_sock <= 0); /* Fork a child process to serve the client */ if ((pid = fork()) != 0) { /* parent process can close the connect and quit */ close(con_sock); } else { /* The child process will handle the client, and the quit when finished. */ handle_req(); exit(1); } } usage() { fprintf(stderr, "usage homesrvd [-p port]\n"); exit(1); } extern int errno; /* handle_req() will get input from the client, parse it and write the result back to the client. In this case, it will accept a number, either integer or float-point value, and return twice the number. It will repeat until the input is string "quit". */ handle_req() { char buff[8192]; int lg, flag, srv1, is_float, result_i; char *filename, *c, *p; struct stat statres; char req[1024]; double result_f; flag = 1; while (flag) { /* Try to repeat until read something from the client, unless the connection is broken. */ do { lg = read(con_sock, req, 1024); if (lg == -1 && errno == EBADF) goto error; } while (lg <= 0); /* Assume the input will be integer first. */ is_float = 0; if (req[lg - 1] != '\n' || req[lg - 2] != '\r') { sprintf(req, "Error: Unknown input\r\n"); write(con_sock, req, strlen(req)); continue; } /* Get rid of the trailing new line character and carriage return character. */ req[lg - 2] = '\0'; /* Get the first part of the line only. (Separated by space.) */ c = strtok(req, " "); /* Empty line */ if (c == NULL) { sprintf(req, "Error: Unknown input\r\n"); write(con_sock, req, strlen(req)); continue; } /* quit */ if (strncmp(c, "quit", 4) == 0) { flag = 0; break; } /* Check every character to make sure the input is a number, determining it is an integer or not on the way. */ for (p = c; *p /* != NULL */ ; p ++) { if (!isdigit(*p)) { if (*p != '.' || is_float) { /* If the character is not a digit, and not a decimal point, then it is not a number. If it is a decimal point, but there is already another one, then it is not a legal number. */ sprintf(req, "Error: Unknown input\r\n"); write(con_sock, req, strlen(req)); is_float = -1; break; } else /* If we have one decimal point, then the number will not be an integer. */ is_float = 1; } } if (is_float == 1) { /* A float-point number */ result_f = atof(c) * 2; sprintf(req, "%f\r\n", result_f); write(con_sock, req, strlen(req)); } else if (is_float != -1) { /* An integer */ result_i = atoi(c) * 2; sprintf(req, "%d\r\n", result_i); write(con_sock, req, strlen(req)); } } /* Some connection error happened, or quit the loop because receiving "quit" from the client. Will close connection and exit this function. */ error: close(con_sock); } main(int argc,char **argv) { int lg; /* Shift the parameter */ argc--; argv++; while (argc > 0) { if (argv[0][0] != '-') usage(); switch (argv[0][1]) { case 'p': /* Set port number of the server */ srv_port = atoi(argv[1]); argv += 2; argc -= 2; break; default: usage(); } } /* Intercept CHILD signal. This signal occurs when a child process changes its status. In this program, it usually means when a child process calls exit() to end itself. */ sigset(SIGCHLD, child_end); /* Intercept some signals which will end this process so we can close connection before quit it. */ signal(SIGTERM, signal_handler); signal(SIGQUIT, signal_handler); signal(SIGINT, signal_handler); /* Setup the socket and the port */ init_servconnection(); /* Wait for connection */ do { attenteconnection(); } while (1); }