I am trying to build a server which can serve for many clients.
The server just do a simple job: get the input string from client and then change each letter to upper case.
But the problem is, when I try to shut down one client, for example, type “Ctrl-C”, then my OS will be shut down suddenly.
I use the Ubuntu 10.10 and CentOS to test my program, but always the same problem.
Here’s my source code:
/* client.c */
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAXLINE 80
#define SERV_PORT 8000
int main (void)
{
struct sockaddr_in servaddr, cliaddr;
char buf[MAXLINE];
int sockfd, n;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
while (fgets(buf, MAXLINE, stdin) != NULL) {
write(sockfd, buf, strlen(buf));
n = read(sockfd, buf, MAXLINE);
if(n == 0) printf("Connect closed\n");
else write(STDOUT_FILENO, buf, n);
}
close(sockfd);
return 0;
}
/* server */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAXLINE 80
#define SERV_PORT 8000
void sigchld_func (int signo) {
wait(NULL);
}
int main (void)
{
struct sockaddr_in servaddr, cliaddr;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
int listenfd, connfd;
socklen_t cliaddr_len;
int n, i;
pid_t pid;
signal(SIGCHLD, sigchld_func);
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, 20);
printf("Accepting connections...\n");
while (1) {
cliaddr_len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
if ((pid = fork()) < 0) {
perror("fork error!");
exit(1);
} else if (pid > 0) {
close(connfd);
} else {
close(listenfd);
while (1) {
n = read(connfd, buf, MAXLINE);
if (n <= 0) {
printf("Connection closed\n");
break;
}
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str));
printf("Received from %s at port %d\n", str, ntohs(cliaddr.sin_port));
for (i = 0; i < n; i++)
buf[i] = toupper(buf[i]);
write(connfd, buf, n);
}
close(connfd);
}
}
return 0;
}
Your server code is causing a fork bomb, and you’re not seeing it properly because you’re not checking the return value of
accept.The root cause is that in the child that reads/writes to the client, after the connection is closed, you’re not either calling
exitor returning out of main.So the child process stays in the toplevel
while(1)loop, tries toacceptonlistenfd(but you closed that one, which is good).acceptfails, and you fork regardless. Tight loops of forks will slow down your computer, the scheduler can’t deal with them properly (unless you have counter-measures in place).So exit out of the program after
close(connfd), and add more error checking in your code.