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);
}