csocketsforkdefunct

Killing forked process in a socket server


I've written a socket based multi client server and a client as an assigment, but I don't seem to be able to get rid of forked processes. Every time I close the client, or enter the exiting command, the process doesn't seem to close. When checked ps aux| grep server there is a defuct process. How can I get rid of them, what am I doing wrong when closing forked prosses.

The server:

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>

void error(char *msg)
{
    perror(msg);
    exit(1);
}

void doprocessing (int sock)
{
   int n;
   char buffer[5];
   time_t rawtime;
   char tim[22];
   char dat[20];
   char day[16];
   char yer[18];

   while(1)
   {
     bzero(buffer,5);
     n = read(sock,buffer,5);

     if (n < 0) error("ERROR reading from socket");

     printf("Got %.3s command.\n",buffer);

     if (strcasecmp(buffer, "tim\n") == 0)
     {
        rawtime = time(NULL);
        strncpy(tim, "Current time: ", 14);
        strncpy(tim+14, (ctime(&rawtime))+11, 8);
        n = write(sock, tim, 22);
     }
     else if (strcasecmp(buffer, "dat\n") == 0)
     {
        rawtime = time(NULL);
        strncpy(dat, "Current date: ", 14);
        strncpy(dat+14, (ctime(&rawtime))+4, 6);
        n = write(sock, dat, 20);
     }
     else if (strcasecmp(buffer, "day\n") == 0)
     {
        rawtime = time(NULL);
        strncpy(day, "Current day: ", 13);
        strncpy(day+13, (ctime(&rawtime)), 3);
        n = write(sock, day, 16);
     }
     else if (strcasecmp(buffer, "yer\n") == 0)
     {
        rawtime = time(NULL);
        strncpy(yer, "Current year: ", 14);
        strncpy(yer+14, (ctime(&rawtime))+20, 4);
        n = write(sock, yer, 18);
     }
     else if (strcasecmp(buffer, "com\n") == 0)
     {
        n = write(sock, "TIM - current time\nDAT - Month and day\nDAY - current weekday\nYER - Year\nEXT - exit", 82);
     }
     else if (strcasecmp(buffer, "ext\n") == 0)
     {
        n = write(sock, "Exiting", 7);
        break;
     }
     else  n = write(sock, "Wrong command enter COM to see commands.",40);

     if (n < 0) error("ERROR writing to socket");}
   }

int main(int argc, char *argv[])
{
    int sockfd, newsockfd, portno, clilen, n;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int pid;

    if (argc < 2)
    {
        fprintf(stderr, "ERROR, no port provided");
        exit(1);
    }

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd < 0) error("ERROR opening socket");

    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(argv[1]);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(portno);
    serv_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding");

    listen(sockfd, 5);
    clilen = sizeof(cli_addr);

    while(1)
    {
         newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
         if (newsockfd < 0) error("ERROR on accept");


         pid = fork();

         if (pid < 0) error("ERROR on fork");

         if (pid == 0)
         {
             close(sockfd);
             doprocessing(newsockfd);
             exit(-1);
         }
         else close(newsockfd);
    }
    close(sockfd);
    return 0;
}

The Client:

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

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char rbuffer[256];
    char sbuffer[256];

    if (argc < 3)
    {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }

    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd < 0) error("ERROR opening socket");

    server = gethostbyname(argv[1]);

    if (server == NULL)
    {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(portno);

    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) error("ERROR connecting");

    while(1)
    {
       printf("Enter a command: ");
       bzero(sbuffer,sizeof(sbuffer));
       fgets(sbuffer,255,stdin);
       n = write(sockfd,sbuffer,5);
       if (n < 0) error("ERROR writing to socket");

       bzero(rbuffer,sizeof(rbuffer));
       n = read(sockfd,rbuffer,255);
       if (n < 0) error("ERROR reading from socket");

       printf("%s\n",rbuffer);

       if (strcasecmp(sbuffer, "ext\n") == 0) break;
    }
    close(sockfd);
    return 0;
}

Solution

  • A process is going to be visible in ps output as 'defunct' (sometimes called zombie process) until it's exit status is going to be collected with wait() or waitpid().

    There are following ways of getting rid of those zombie processes:

    1. Wait for child completion using wait() or waitpid() in parent process. Obviously, it's hard to do anything else in the parent this way.
    2. Create a separate thread immediately after spawning a child and waitpid inside this thread.
    3. In your parent, install a handler for SIGCHLD signal and waitpid() inside this handler.
    4. If your system allows that, set to ignore SIGCHLD signal.