int
run ()
{
char str[100];
int listen_fd, comm_fd;
struct sockaddr_in servaddr;
listen_fd = socket (AF_INET, SOCK_STREAM, 0);
bzero (&servaddr, sizeof (servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons (INADDR_ANY);
servaddr.sin_port = htons (8080);
int n;
bind (listen_fd, (struct sockaddr *) &servaddr, sizeof (servaddr));
listen (listen_fd, 10);
int pid;
while (1)
{
comm_fd = accept (listen_fd, (struct sockaddr *) NULL, NULL);
if (comm_fd < 0)
printf ("ERROR on accept");
//fork new process
pid = fork ();
if (pid < 0)
{
printf ("ERROR in new process creation");
}
if (pid == 0)
{
close (listen_fd);
bzero (str, 256);
n = read (comm_fd, str, 255);
if (n < 0)
printf ("ERROR reading from socket");
printf ("Here is the message: %s\n", str);
n = write (comm_fd, "I got your message", 18);
if (n < 0)
printf ("ERROR writing to socket");
close (comm_fd);
}
else
{
close (comm_fd);
}
}
printf ("readIn Exit!");
exit (1);
}
为什么这会成为一个二战炸弹,我如何让它作为一个可以处理客户端丢失的多客户端服务器?
有些帖子暗示每个用户的最大进程太低,但我的709.对我来说这件作品似乎很多(我使用的是mac书)
我也尝试了以下方法,但结果相同:
while((comm_fd = accept(listen_fd, (struct sockaddr *) NULL, NULL))){
pid = fork();
if(pid == 0){
close(listen_fd);
while(1){
bzero( str, 100);
read(comm_fd, str, 100);
printf("S: %s", str);
write(comm_fd, str, strlen(str)+1);
sleep(1);
}
exit(1);
} else {
close(listen_fd);
}
}
答案 0 :(得分:2)
这是一个叉炸弹,因为这部分:
while (1) {
pid = fork();
if (pid == 0) { /* child */
...read()...write()...
} else { /* parent */
close(comm_fd);
}
}
这是一个无限循环,其中父级继续分叉和关闭comm_fd。成功读写后,每个孩子将在下一次迭代中进行分叉。重复,直到所有进程槽都泄漏。
您的第二个代码段会耗尽所有流程广告位,因为父级需要wait()
或wait4()
来收集子级的退出状态。在完成此过程之前,进程仍处于僵尸状态。每个僵尸占据一个进程槽。
就像malloc需要相应的免费,fork需要等待。
PS:C中的规范无限循环写为for(;;)
,以避免while(1)
中的常量值布尔值。
答案 1 :(得分:1)
这是一个fork炸弹,因为你永远不会终止这个孩子,所以它继续在accept()
给出错误但不终止进程的情况下循环运行。所以它继续fork()
并且永远这样做。
修改如下代码:
if (pid == 0)
{
close (listen_fd);
bzero (str, 256);
n = read (comm_fd, str, 255);
if (n < 0)
printf ("ERROR reading from socket");
printf ("Here is the message: %s\n", str);
n = write (comm_fd, "I got your message", 18);
if (n < 0)
printf ("ERROR writing to socket");
close (comm_fd);
exit(some_value); // terminates the child
}
要清理系统表,您还需要等待终止子项:
else
{
close (comm_fd);
while (waitpid(0,NULL,WNOHANG)!=-1); // clean system tables non blocking
}
这不是表格的最佳方式,但它相对有效,至少足够。最好的方法是捕获信号SIGCHLD
并清理处理程序中的表。