I'm having trouble converting a server from using signal() to
sigaction().

The original client-server pair works fine.

But the sigaction() version seems to create spurious child processes every so often after another child has terminated.

What have I missed?



Client Code:

Code:
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>

/* client */

void child_func(int childnum);

int main(int argc, char *argv[])
{
    int nchildren = 1;
    int pid;
    int x;
    if (argc > 1) 
    {
        nchildren = atoi(argv[1]);
    }

    for (x = 0; x < nchildren; x++) 
    {
        if ((pid = fork()) == 0) 
        {
            child_func(x + 1);
            exit(0);
        }
    }
    
    wait(NULL);
    return 0;
}

void child_func(int childnum)
{
    int sock;
    struct sockaddr_in sAddr;
    char buffer[25];
    memset((void *) &sAddr, 0, sizeof(struct sockaddr_in));

    sAddr.sin_family = AF_INET;
    sAddr.sin_addr.s_addr = INADDR_ANY;
    sAddr.sin_port = 0;

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    bind(sock, (const struct sockaddr *) &sAddr, sizeof(sAddr));
    
    sAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    sAddr.sin_port = htons(1972);
    if (connect(sock, (const struct sockaddr *) &sAddr, sizeof(sAddr)) != 0) 
    {
        perror("client");
        return;
    }
    
    snprintf(buffer, 128, "data from client #%i.", childnum);
    sleep(1);
    printf("child #%i sent %i chars\n", childnum, send(sock, buffer,
    strlen(buffer), 0));
    sleep(1);
    printf("child #%i received %i chars\n", childnum,
    recv(sock, buffer, 25, 0));
    sleep(1);
    close(sock);
}
Original Server Code:

Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <signal.h>
#include <netdb.h>
#include <unistd.h>

/* original server */

void sigchld_handler(int signo)
{
    while (waitpid(-1, NULL, WNOHANG) > 0);
}

int main(void)
{
    struct sockaddr_in sAddr;
    int listensock;
    int newsock;
    char buffer[25];
    int result;
    int nread;
    int pid;
    int val;

    listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    val = 1;
    result = setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
    if (result < 0) 
    {
        perror("server2");
        return 0;
    }

    sAddr.sin_family = AF_INET;
    sAddr.sin_port = htons(1972);
    sAddr.sin_addr.s_addr = INADDR_ANY;

    result = bind(listensock, (struct sockaddr *) &sAddr, sizeof(sAddr));
    if (result < 0) 
    {
        perror("server2");
        return 0;
    }

    result = listen(listensock, 5);
    if (result < 0) 
    {
        perror("server2");
        return 0;
    }

    signal(SIGCHLD, sigchld_handler);

    while (1) 
    {
        newsock = accept(listensock, NULL, NULL);
        if ((pid = fork()) == 0) 
        {
            printf("child process %i created.\n", getpid());
            close(listensock);

            nread = recv(newsock, buffer, 25, 0);
            buffer[nread] = '\0';
            printf("%s\n", buffer);
            send(newsock, buffer, nread, 0);
            close(newsock);
            printf("child process %i finished.\n", getpid());
            exit(0);
        }

        close(newsock);
    }
}
Sigaction Server Code:

Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <signal.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>

/* sigaction server */

void sigchld_handler(int signo);

int main(void)
{
    struct sockaddr_in sAddr = {0};
    struct sigaction san;
    int listensock;
    int newsock;
    char buffer[25];
    int result;
    int nread;
    int pid;
    int val;
    
    memset(&san,0,sizeof(san));
    san.sa_handler = sigchld_handler;
   
    listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    val = 1;
    result = setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
    if (result < 0) 
    {
        perror("server2");
        return 0;
    }

    sAddr.sin_family = AF_INET;
    sAddr.sin_port = htons(1972);
    sAddr.sin_addr.s_addr = INADDR_ANY;

    result = bind(listensock, (struct sockaddr *) &sAddr, sizeof(sAddr));
    if (result < 0) 
    {
        perror("server2");
        return 0;
    }

    result = listen(listensock, 5);
    if (result < 0) 
    {
        perror("server2");
        return 0;
    }

    sigaction(SIGCHLD,&san,NULL);
    while (1) 
    {
        newsock = accept(listensock, NULL, NULL);
        if ((pid = fork()) == 0) 
        {
            printf("child process %i created.\n", getpid());
            close(listensock);

            nread = recv(newsock, buffer, 25, 0);
            buffer[nread] = '\0';
            printf("%s\n", buffer);
            send(newsock, buffer, nread, 0);
            close(newsock);
            printf("child process %i finished.\n", getpid());
            exit(0);
        }

        close(newsock);
    }
}

void sigchld_handler(int signo)
{
    while (waitpid(-1, NULL, WNOHANG) > 0);
}