Tuesday, January 06, 2009

Sample C Server which handles zombie processes

After a bit of googling I managed to create a simple Server (written in C) which accepts connection on port 5000 and spawns a new thread to handle each request:



#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <signal.h>

#define MAX_CLIENT 10

void zombie_handler(int iSignal)
{
signal(SIGCHLD,zombie_handler); //reset handler to catch SIGCHLD for next time;
int status;
pid_t pid;

pid = wait(&status); //After wait, child is definitely freed.
printf("pid = %d , status = %d\n", pid, status);
}

int main(int argc, char *argv[])
{
int tcp_sockfd, k, portno=0, tcp_newsockfd, n;
struct sockaddr_in myServer, myClient;
char bufferin[256],bufferout[256],ipaddress[20],hostname[50];
char s[INET6_ADDRSTRLEN];
struct hostent *host;
pid_t pid=-1;

signal(SIGCHLD,zombie_handler);

//////////////////// Create a TCP Socket and get the port number dynamically

tcp_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (tcp_sockfd < 0)
error("ERROR opening TCP socket");

bzero((char *) &myServer, sizeof(myServer));
myServer.sin_family = AF_INET;
myServer.sin_addr.s_addr = htonl(INADDR_ANY);
myServer.sin_port = htons(5000);
if (bind(tcp_sockfd, (struct sockaddr *) &myServer, sizeof(myServer)) < 0)
error("ERROR on binding");

portno = ntohs(myServer.sin_port);

if(gethostname(hostname,50) == -1) // get hostname of the chat server machine
error("ERROR on gethostname");
host = gethostbyname(hostname); // get host information
strcpy(ipaddress,(char *)inet_ntoa(*(long*)host->h_addr_list[0])); //get IP Address string format

printf("Chat Server IP Address : %s\n",ipaddress);
printf("Chat Server Port Number : %d\n",portno);

//////////////////////////////////////// Now wait for connection from Client
if(listen(tcp_sockfd,MAX_CLIENT) == -1)
error("ERROR on listen");

while(1)
{
printf("Waiting for connection...\n");
k=sizeof(myClient);
tcp_newsockfd = accept(tcp_sockfd,(struct sockaddr *)&myClient,&k);
if (tcp_newsockfd == -1) {
printf("error in accept\n");
continue;
}

if (!fork()) { // this is the child process
close(tcp_sockfd); // child doesn't need the listener
if (send(tcp_newsockfd, "Hello, world!", 13, 0) == -1)
perror("send");
close(tcp_newsockfd);
exit(0);
}
close(tcp_newsockfd); // parent doesn't need this


}
close(tcp_sockfd);

return 0;
}



Here I simply write a string (Hello World!) to the client. You may perform multiple reads/writes.

The zombie_handler function ensures that no zombie processes are created once the child exists.