Программа на сервере C не может быть разветвлена - PullRequest
0 голосов
/ 18 сентября 2018

У меня есть серверная программа, написанная на 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 голосов
/ 18 сентября 2018

Основываясь на предложении @immibus и @ ShadowRanger, я изменил код следующим образом, и он работал нормально (добавлен сигнальный вызов за пределами цикла принятия моего сервера):

 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);
 }
0 голосов
/ 18 сентября 2018

Вы не можете выполнить разветвление, вероятно, потому что вы установили пользовательское или системное ограничение на количество процессов, которые вы можете создать. Причина этого заключается в том, что, пока вы заставляете детей правильно выходить из себя, вы не «ждете» их потом в родителе. Это означает, что процесс не очищается и для него выделяются определенные ресурсы.

Один из способов справиться с этим - заставить родителя ответить на SIGCHLD, который является сигналом, который ОС отправляет родителю, чтобы сообщить ему о прекращении ребенка.

Используя пример из https://beej.us/guide/bgnet/html/multi/clientserver.html#simpleserver, вы добавляете функцию для ОС для вызова события, а затем используете вызов sys для информирования ОС о своем намерении использовать эту функцию для этого сигнала.

Вы добавляете

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

Приятно то, что вы можете использовать этот метод, чтобы реагировать на другие сигналы от ОС, а также распространять его после смерти ребенка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...