C服务器程序无法分叉

时间:2018-09-18 01:08:52

标签: c fork

我有一个用C编写的服务器程序,应该可以接受请求并派生一个子进程来处理该请求。这是相关代码:

    client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c); 
    if (client_sock < 0) {
        perror("accept failed");
        return 1;
    }

    if((pid = fork()) < 0){
        perror("fork"); 
        exit(1);
    }else if (pid == 0){ 
        close(socket_desc); 
        /* code to handle request */
        close(client_sock);

        // exit(0);
        kill(getpid(), SIGKILL);
    }

    close(client_sock);

我想问的是,在子进程中使用exit(0)kill()时,该进程是否被杀死?当我运行上述程序并向其发送请求时,在大约10000个请求之后,fork调用失败,并显示消息fork: Resource temporarily unavailable。如果我可靠地杀死了分叉的进程,那么为什么fork调用会失败?另外,如何在不更改系统限制的情况下进行管理?

2 个答案:

答案 0 :(得分:0)

您无法进行分叉,可能是因为您在可创建的进程数上达到了用户或系统限制。这样做的原因是,当您让孩子正确离开自己时,您之后就不会在父母中“等待”他们了。这意味着该进程不会被清理,并且会为其分配某些资源。

一种解决方法是让父母对SIGCHLD做出响应,这是OS发送给父母的信号,通知其孩子已终止。

使用https://beej.us/guide/bgnet/html/multi/clientserver.html#simpleserver中的示例,您为操作系统添加了一个函数来在事件发生时进行调用,然后使用sys调用来通知OS您打算对该信号使用此函数的意图。

您添加

void sigchld_handler(int s)
{
    // waitpid() might overwrite errno, so we save and restore it:
    int saved_errno = errno;

    while(waitpid(-1, NULL, WNOHANG) > 0);

    errno = saved_errno;
}

并在您的主要功能中的某个时候完成

struct sigaction sa;

sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
    perror("sigaction");
    exit(1);
}

令人高兴的是,您可以使用此方法对来自操作系统的其他信号做出反应,并在孩子死后将其扩展。

答案 1 :(得分:0)

基于@immibus和@ShadowRanger的建议,我按如下方式修改了代码,并且效果很好(服务器外部的信号调用接受了while循环):

 signal(SIGCHLD, SIG_IGN);
 ...
 while (1) {
    c = sizeof(struct sockaddr_in);
    client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c); 
    if (client_sock < 0) {
        perror("accept failed");
        return 1;
    }

    if((pid = fork()) < 0){
        perror("fork"); 
        exit(1);
    }else if (pid == 0){ 
        close(socket_desc); 
        /* code to handle request */
        close(client_sock);

        // exit(0);
        kill(getpid(), SIGKILL);
    }

    close(client_sock);
 }