Since these child servers terminate when their respective
clients terminate, and when these child servers terminate,
their parent (i.e., the original server) is still alive and has
made no attempt to claim its children, these child servers
will become
zombies
. Since each zombie takes up one slot
Server
child
server 1
child
server 2
child
server 3
client 1
client 1
client 1

ICT310 Network and Sockets
_____________________________________________________________________________________
Page 40 / 72
in the process table, these zombies may quickly accumulate
and exhaust the process table.
To prevent zombies from wasting system resources, the
server must claim its child when it terminates. Since when a
child dies, it sends the signal
SIGCHLD
to its parent
process, we can catch this signal in the parent process and
use
waitpid
to claim the zombie.
void claim_children()
{ pid_t
pid=1;
while (pid > 0)
pid = waitpid(0,(int *)0, WNOHANG);
}
Of course, we need to set up the signal handler for
SIGCHLD
first:
struct sigaction act;
act.sa_handler = claim_children;
sigemptyset(act.sa_mask);
act.sa_flags = SA_NOCLDSTOP;
sigaction(SIGCHLD, (struct sigaction *) &act,
(struct sigaction *) 0);
Usually
SIGCHLD
is generated when a child is terminated or
stopped (job control). If we do not want the
SIGCHLD
generated when the child is
stopped
, we can set the option
SA_NOCLDSTOP
when installing the signal handler for
SIGCHLD
. In the above example, the handler is only called
when a child terminates. It will not be called when a child is
stopped.
(4)
Since a signal may “interrupt” a slow system call, i.e.,
causing it to return prematurely, care must be taken to
prevent malfunction of your programs

ICT310 Network and Sockets
_____________________________________________________________________________________
Page 41 / 72
while(1)
{
nsd=accept(...);
if (nsd < 0)
if (errno == EINTR)
continue;
}
We have incorporated the above changes in our
Example 5
in the next section.

ICT310 Network and Sockets
_____________________________________________________________________________________
Page 42 / 72
21. Example 5
/*
*
ser5.c
a much improved (still not perfect, though) version
*
of "ser4.c".
*/
#include
<string.h>
/* strlen(), strcmp() etc */
#include
<errno.h>
/* extern int errno, EINTR, perror() */
#include
<signal.h>
/* SIGCHLD, sigaction() */
#include
<sys/types.h>
/* pid_t, u_long, u_short */
#include
<sys/socket.h> /* struct sockaddr, socket(), etc */
#include
<sys/wait.h>
/* waitpid(), WNOHAND */
#include
<netinet/in.h> /* struct sockaddr_in, htons(), htonl(), */
/* and INADDR_ANY */
#define
BUFSIZE
256
#define
SERV_TCP_PORT
40001
/* server port no */
void claim_children()
{
pid_t pid=1;
while (pid>0) { /* claim as many zombies as we can */
pid = waitpid(0, (int *)0, WNOHANG);
}
}
void daemon_init(void)
{
pid_t
pid;
struct sigaction act;
if ( (pid = fork()) < 0) {
perror("fork"); exit(1);
} else if (pid > 0)
exit(0);
/* parent goes bye-bye */
/* child continues */
setsid();
/* become session leader */
chdir("/");
/* change working directory */
umask(0);
/* clear file mode creation mask */
/* catch SIGCHLD to remove zombies from system */
act.sa_handler = claim_children; /* use reliable signal */
sigemptyset(&act.sa_mask);
/* not to block other signals */
act.sa_flags
= SA_NOCLDSTOP;
/* not catch stopped children */
sigaction(SIGCHLD,(struct sigaction *)&act,(struct sigaction *)0);
/* note: a less than perfect method is to use
signal(SIGCHLD, claim_children);
*/
}
void reverse(char *s)

ICT310 Network and Sockets
_____________________________________________________________________________________
Page 43 / 72
{
char c;
int i, j = strlen(s);
for (i=0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i]; s[i] = s[j]; s[j] = c;
}
}
void serve_a_client(int sd)
{

