The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
Проблема с серверной частью программы, !*! Dima, 01-Сен-02, 23:16  [смотреть все]
Люди, выручайте, не фига не могу понять, в чём  трабл, вот пример кода, а ниже расскажу в чём проблема.

main()
...
signal(SIGCHLD, sig_child);
...
socket(...);
bind(...);
listen(...);
...
daemon(...);

// Главный цикл
for (;;)
{
  // тут с помощью select слушаются нужные дескрипторы
  // потом выполняются действия в зависимости от того, что там в селекте
  // случилось, на интересует inet дескриптор, значит делаем если это
  // он accept...
  ...
  if ( (ns = accept(sockfd, (struct sockaddr *)&client, &cl_len)) == -1)
  {
   ...
   continue;
  }
  // мы тут, если соединение прошло удачно, делаем форк.

  if ( fork() == 0 )
  {
   //дочерний процесс
   childproc();
   close(ns);
   exit(0);
  }
  // а тут мы в родительском и ns нам не нужет здесь
  close(ns);
}
exit(0); // NOT REACHED
}

void sig_child(int sig)
{
//функция для того, чтобы при выходе дочернего процесса, родительский
//принял его pid. (ИНАЧЕ ДОЧЕРНИЙ ПРОЦЕСС ОСТАНЕТСЯ КАК ЗОМБИ)
int status;

while (waitpid(-1, &status, WNOHANG) > 0) ;
}

Проблема вот какая, при таком вот раскладе первое подключение происходит на ура, при попытке второго подключения, соккет не отвечает (но демон его слушает, может в селекте проблема?).
Если я убираю обработку сигнала SIGCHLD, то всё работает нормально, но остаются зомби процессы от дочерних...
Как можно это решить?

Спасибо всем!

  • RE: Проблема с серверной частью программы, !*! Арлекин, 08:02 , 02-Сен-02 (1)
    В соляре SIGCHLD ловить не обязательно. Можно просто временами вызывать wait(&status)если ПОРОЖДЕННЫЙ процесс УЖЕ закончился, она все равно ответит кодом процесса, который закончился. Подробнее не помню, но в манах все есть.
    Ну и проще всего, хотя и неправильно в общем случае, килять в подпроцессе самого себя, "наизлете". Вот только тогда родительский wait получит код убийства (SIGTERM, SIGINT, ...).
    • RE: Проблема с серверной частью программы, !*! Dima, 14:07 , 02-Сен-02 (2)
      >В соляре SIGCHLD ловить не обязательно. Можно просто временами вызывать wait(&status)если ПОРОЖДЕННЫЙ
      >процесс УЖЕ закончился, она все равно ответит кодом процесса, который закончился.
      >Подробнее не помню, но в манах все есть.
      >Ну и проще всего, хотя и неправильно в общем случае, килять в
      >подпроцессе самого себя, "наизлете". Вот только тогда родительский wait получит код
      >убийства (SIGTERM, SIGINT, ...).

      К сожалению у меня не солярка.... я под openbsd пишу, на счёт килять самого себя, идея не плохая, надо будет попробовать! Спасибо!


      • RE: Проблема с серверной частью программы, !*! Dima, 12:02 , 03-Сен-02 (3)
        >>В соляре SIGCHLD ловить не обязательно. Можно просто временами вызывать wait(&status)если ПОРОЖДЕННЫЙ
        >>процесс УЖЕ закончился, она все равно ответит кодом процесса, который закончился.
        >>Подробнее не помню, но в манах все есть.
        >>Ну и проще всего, хотя и неправильно в общем случае, килять в
        >>подпроцессе самого себя, "наизлете". Вот только тогда родительский wait получит код
        >>убийства (SIGTERM, SIGINT, ...).
        >
        >К сожалению у меня не солярка.... я под openbsd пишу, на счёт
        >килять самого себя, идея не плохая, надо будет попробовать! Спасибо!

        Добавил в конце дочернего тела  kill(getpid(),SIGKILL);
        и тот же результат, остаётся зомби процесс, родительский в любом случае должен обработать сообщение от дочернего...

        Чего делать, на знаю...


        • RE: Проблема с серверной частью программы, !*! Dima, 12:21 , 03-Сен-02 (4)
          Вся проблема-то ещё и в том, что родительский процесс перестаёт принимать соединения если даже я просто сделаю обработчик дочерних сигналов ( signal(SIGCHLD, sig_child); ) а в теле функции sig_child будет пусто.
          • RE: Проблема с серверной частью программы, !*! Арлекин, 12:50 , 03-Сен-02 (5)
            Ты return-то не забыл в перехватчик воткнуть ? А то она не факт, что вернется. Проверено.
            • RE: Проблема с серверной частью программы, !*! Dima, 12:55 , 03-Сен-02 (6)
              >Ты return-то не забыл в перехватчик воткнуть ? А то она не
              >факт, что вернется. Проверено.

              Возможно что и забыл, как это например делается?


              • RE: Проблема с серверной частью программы, !*! Арлекин, 12:58 , 03-Сен-02 (7)
                void sig_catcher( int sig_num )
                {
                  /* пустой перехватчик */
                  return;   // чтоб гарантированно вернул стек на точку вызова
                }
                • RE: Только 11-й сигнал не лови так, !*! Арлекин, 12:59 , 03-Сен-02 (8)
                  А то kernel panic может случиться )
                  • RE: Только 11-й сигнал не лови так, !*! Dima, 13:15 , 03-Сен-02 (9)
                    >А то kernel panic может случиться )

                    Всё равно не фига...
                    Я сделал чтобы прога писала стадию выполнения главного цикла, вот что получаю:

                    Tue Sep  3 13:03:02 2002: go to background sucessfull
                    Tue Sep  3 13:03:02 2002: start complete. accept connections!
                    main loop... next select (самое начало, ждём select();)
                    main loop... after select (в данном случае получили соединеие и это место уже после селекта)
                    main loop... next accept (Перед принятием соединения)
                    Accept connection... next fork (Соединение успешное, делаем форк)
                    main loop... next select (почему-то процесс перешёл на начало цикла..)
                    fork() (делаем форк)
                    child (это функция из дочернего процесса (она читает сокет и отправлет что надо в него, потом просто выходит))
                    Tue Sep  3 13:04:10 2002: Login successful (login 'al' from host '172.16.32.3' action 0) (результат успешной авторизации клиентского приложения)
                    exit(0) //from child proc.
                    sig_child... (это когда родитель выполняет функцию по событию от дочернего процесса)
                    main loop... after select (почему-то оказывается что селект что-то получил, и дальше ни чего не происходит.)

                    куски кода:

                    void sig_child(int sig)
                    {
                    int status;

                    while (waitpid(-1, &status, WNOHANG) > 0) ;

                    fprintf(logfile, "sig_child...\n");
                    fflush(logfile);

                    return;
                    }

                    /* main cycle  */
                    for(;;)
                    {
                      fprintf(logfile, "main loop... next select\n");
                      fflush(logfile);

                      set = master;
                      select(FD_SETSIZE, &set, NULL, NULL, NULL);
                      fprintf(logfile, "main loop... after select\n");
                      fflush(logfile);
                      
                      if ( FD_ISSET(ctlsock, &set) )
                      { ctl_read_upcall(ctlsock); }

                      if ( FD_ISSET(sockfd, &set) )
                      {
                       cl_len = sizeof(struct sockaddr_in);
                       fprintf(logfile, "main loop... next accept\n");
                       fflush(logfile);
                      
                       if ( (newsockfd = accept(sockfd, (struct sockaddr *)&client, &cl_len)) == -1)
                       {
                        c_error++;
                        time(&timeval); memcpy(ctimeval, ctime(&timeval), strlen(ctime(&timeval))-1);
                        fprintf(logfile, "%s: accept socket error (*)\n", ctimeval);
                        fflush(logfile);
                        continue;
                       }
                       fprintf(logfile, "Accept connection... next fork\n", ctimeval);
                       fflush(logfile);

                       /* Create new process (fork) and etc... */
                       c_auth_accept++;
                       if ( fork() == 0 )
                       {
                        fprintf(logfile, "fork()\n");
                        fflush(logfile);
                        childproc();
                        close(newsockfd);
                        exit(0);
                       }
                       close(newsockfd);
                      }
                    }

                    • RE: Только 11-й сигнал не лови так, !*! Арлекин, 13:38 , 03-Сен-02 (10)
                      Поставь на каждый вызов по Фпринтфу, чтоли. Хоть ясно станет где конкретно она задумалась. Я последнее время от С отошел несколько, да и как-то нечитабельно выглядит... Уж извини.
                      • RE: Только 11-й сигнал не лови так, !*! Dima, 14:04 , 03-Сен-02 (11)
                        >Поставь на каждый вызов по Фпринтфу, чтоли. Хоть ясно станет где конкретно
                        >она задумалась. Я последнее время от С отошел несколько, да и
                        >как-то нечитабельно выглядит... Уж извини.

                        Ладно, спасибо, буду разбираться....

                        Спасибо!


                    • RE: Только 11-й сигнал не лови так, !*! idle, 23:25 , 03-Сен-02 (12)
                      Вы совсем заговорились :)

                      > Ты return-то не забыл в перехватчик воткнуть ?
                      > А то она не факт, что вернется. Проверено.

                      Значит, надо выкидывать компилятор. Обработчик
                      сигнала - обычная функция, явный return в конце
                      не нужен.

                      Предлагаю скомпилировать оба варианта и сравнить
                      исполняемые файлы с помощью cmp. Они совпадут.

                      > А то kernel panic может случиться )

                      Значит, надо выкидывать ядро, если таким
                      (или другим) способом можно вызвать panic.


                      Если не интересует exit_code порожденных
                      процессов, можно поставить SIG_IGN на SIGCHLD,
                      зомби не будет.

                      Функцией signal() вообще не стоит пользоваться,
                      она ведет себя немного по-разному в разных системах
                      и даже версиях libc. Пользуйтесь sigaction().

                      > main loop... next select (почему-то процесс перешел на начало цикла..)

                      Он и должен перейти, это же parent, fork() вернул не 0.

                      > main loop... after select (почему-то оказывается что селект
                      > что-то получил, и дальше ни чего не происходит.)

                      После того, как child умрет, процессу посылается SIGCHLD
                      (если не SIG_DFL || SIG_IGN). В случае получения процессом
                      не блокированного сигнала, select() вернет EINTR и в set мусор -
                      это нужно проверять!!!! Поэтому и не происходит ничего.
                      Например, очень может быть, что FD_ISSET(ctlsock, &set) == 1,
                      и процесс сидит в ctl_read_upcall(ctlsock).

                      Без обид, лучше бы прочитать man select, man signal etc,
                      чем сразу писать в форум, быстрее бы получилось.

                      P.S. Если каждый раз после fprintf(logfile, ...) стоит
                      fflush(logfile), то на хрена fprintf(), если есть write()?

                      • RE: Только 11-й сигнал не лови так, !*! Арлекин, 07:47 , 04-Сен-02 (13)
                        > Ты return-то не забыл в перехватчик воткнуть ?
                        > А то она не факт, что вернется. Проверено.
                        >
                        >Значит, надо выкидывать компилятор. Обработчик
                        >сигнала - обычная функция, явный return в конце
                        >не нужен.
                        Вот тебе пример ситуации - спарковский компилер именно так и делает. Не всегда корректно идет из перехватчиков - толи longjmp хочет, толи еще чего - не искал. Но он ЛИЦЕНЗИОННЫЙ. И ОРАКЛ на "боевых" спарковских системах тоже. И в лицензии к последнему черным по белому написано - все разработки только лицензированными для платформы продуктами из списка. Список есть. gcc, etc в списке нет. Мне выкинуть спарковский компилер и штрафы, случись чего, ты платить будешь ? :) По мне проще пустой ретурн поставить.

                        > А то kernel panic может случиться )
                        >
                        >Значит, надо выкидывать ядро, если таким
                        >(или другим) способом можно вызвать panic.
                        Не буду ввязываться в длительную дискуссию, но если уж и выкидывать ядра, то те которые помирают молча. Очень любили это мандрейк 7.какой-то и Valinux, например. А соляркина паника есть ничто иное как обычное сообщение. Еще ни разу не то что ядро не сдохло, но и лишнего процесса не прибилось. А корки в 2гига регулируются ulimit'ом. Оракляндцы - вот большие спецы вызывать такие ситуации, и если бы после каждой приходилось лечить ось или железку я в первую очередь избавился бы от оси. :)


                        • RE: Только 11-й сигнал не лови так, !*! Dima, 11:02 , 04-Сен-02 (14)
                          Сделал я вот так:

                          memset(&act_chd, 0, sizeof(act_chd));
                          act_chd.sa_handler = SIG_IGN;
                          act_chd.sa_flags = SA_NOCLDWAIT;
                          sigemptyset(&act_chd.sa_mask);
                          sigaction(SIGCHLD, &act_chd, (struct sigaction *)0);

                          и зомби всё равно остаются.. ( ос openbsd 3.0 )
                          :((((

                        • RE: Только 11-й сигнал не лови так, !*! Dima, 12:01 , 04-Сен-02 (15)
                          >Сделал я вот так:
                          >
                          > memset(&act_chd, 0, sizeof(act_chd));
                          > act_chd.sa_handler = SIG_IGN;
                          > act_chd.sa_flags = SA_NOCLDWAIT;
                          > sigemptyset(&act_chd.sa_mask);
                          > sigaction(SIGCHLD, &act_chd, (struct sigaction *)0);
                          >
                          >и зомби всё равно остаются.. ( ос openbsd 3.0 )
                          >:((((

                          Всем спасибо!!!!!
                          Я победил эту фигню, короче после очередного вызова select возращал ошибку (-1) и errno было 4 (проблема с сигналами), сделал если селект меньше 0, то continue, неправильно конечно, но работает!!!!
                          Всем спасибо! Извините за шум!


                        • RE: Только 11-й сигнал не лови так, !*! idle, 20:03 , 04-Сен-02 (16)
                          > > > Ты return-то не забыл в перехватчик воткнуть ?
                          > > > А то она не факт, что вернется. Проверено.
                          > >
                          > > Значит, надо выкидывать компилятор. Обработчик
                          > > сигнала - обычная функция, явный return в конце
                          > > не нужен.
                          > >
                          > Вот тебе пример ситуации - спарковский компилер именно так и делает.

                          То есть, этот компилятор генерит разный код для:

                          void f1(int sig) {}
                          void f2(int sig) { return; }

                          Что-то не верится. Может, запостишь asm выход?

                          > А соляркина паника есть ничто иное как обычное сообщение.

                          Ну тут вопрос терминологии, под kernel panic обычно
                          подразумевают крах системы.

                          > короче после очередного вызова select возращал ошибку (-1)
                          > и errno было 4 (проблема с сигналами), сделал если селект меньше 0,
                          > то continue, неправильно конечно, но работает!!!!

                          Это как раз правильно, а errno 4 и есть EINTR.

                        • RE: Только 11-й сигнал не лови так, !*! Арлекин, 07:55 , 05-Сен-02 (17)
                          Давай будем проще. Постить асмы сюда - во-первых дело не совсем правильное, во-вторых ассемблер не интеловский, я в нем никогда не ковырялся и вряд ли что-то пойму сходу, а вникать нет ни времени ни особого желания. Вот тебе результаты с размерами модулей и их исходники:
                          07:48:00 @newgoblin:bin >more test.C
                          #include <stdio.h>
                          void sgc() {
                          return;
                          }
                          main() {
                          }
                          07:47:47 @newgoblin:bin >CC test.C -o test
                          07:48:26 @newgoblin:bin >more test1.C
                          #include <stdio.h>
                          void sgc() {
                          }
                          main() {
                          }
                          07:47:47 @newgoblin:bin >CC test1.C -o test1
                          07:47:56 @newgoblin:bin >ls -laF test*
                          -rwxr-xr-x   1 it_devel voice       8068 Sep  5 07:46 test*
                          -rw-r--r--   1 it_devel voice         54 Sep  5 07:46 test.C
                          -rwxr-xr-x   1 it_devel voice       8064 Sep  5 07:47 test1*
                          -rw-r--r--   1 it_devel voice         46 Sep  5 07:47 test1.C
                          Гнутого "вблизи" нет, как-нибудь потом проверю.
                          Если есть непременное желание удостовериться и выяснить чего там сантехники наваяли, ищи спарк-машину со SPARC C++ 4.1 компилером (solars 6-8 ) и рой. Однако, судя по разности длин, именно 4 байта и есть тот самый jmp.
                          ЗЫЖ Это не первый и не последний пример "уникальности" ЭТОГО компилера.
                        • RE: Только 11-й сигнал не лови так, !*! Арлекин, 08:06 , 05-Сен-02 (18)
                          > А соляркина паника есть ничто иное как обычное сообщение.
                          >Ну тут вопрос терминологии, под kernel panic обычно
                          >подразумевают крах системы.
                          Не совсем так. Kernel Panic - это ситуация, когда ядро не в состоянии гарантированно завершить только процесс - источник аварии, ибо само не гарантирует целостность памяти, семафоров и пр. в окружении того процесса. Я еще не встречал ситуаций, хотя ее можно попробывать смоделировать, чтоб упало само ядро. Речь только о SunSolaris, прошу заметить. Но сам процесс каков! На 6-й оси, где однонитевое ядро, на 2-х процессорном серваке, 2-х гиговая (signed int на СПАРКе 4 байта) корка пишется на диск около минуты и в это время даже консоль не отвечает. Вообще никакой реакции ни на что, и на прерывания в т.ч. Таким образом ядро спасает себя - и это ИМХО правильно, когда одно приложение не может явиться причиной краха всей системы, хоть бы это приложение и самое центровое в ней.


                        • RE: А это от gcc, !*! Арлекин, 08:18 , 05-Сен-02 (19)
                          root@is-tester:/export/home/root$ more test1.C
                          #include <stdio.h>
                          void sgc()
                          {
                          return;
                          }
                          main() {
                          }
                          root@is-tester:/export/home/root$ gcc test1.C -o test1
                          root@is-tester:/export/home/root$ more test.C
                          #include <stdio.h>
                          void sgc()
                          {
                          }
                          main() {
                          }
                          root@is-tester:/export/home/root$ gcc test.C -o test
                          root@is-tester:/export/home/root$ ls -laF test*
                          -rwxr-xr-x   1 root     other       5996 Sep  5 08:21 test*
                          -rw-r--r--   1 root     other         45 Sep  5 08:21 test.C
                          -rw-r--r--   1 root     other      21882 Apr  9 11:17 test.dat
                          -rwxr-xr-x   1 root     other       6004 Sep  5 08:22 test1*
                          -rw-r--r--   1 root     other         53 Sep  5 08:22 test1.C

                        • RE: А это от gcc, !*! idle, 00:49 , 06-Сен-02 (20)
                          > Давай будем проще. Постить асмы сюда - во-первых дело не совсем правильное,

                          А что так? Строгий секрет, государственная тайна?
                          У этого компилятора -S ключ есть? Вот и скажи CC -S на:

                                void f1(int sig) {}
                                void f2(int sig) { return; }

                          Но! Не забудь хотя бы _минимальную_ оптимизацию включить!
                          Не знаю, как твой CC, но gcc без -O (хотя бы) компилирует
                          буквально по тексту - отсюда и разница в размерах.
                          Мне просто любопытно.

                          > Не совсем так. Kernel Panic - это ситуация,

                          Ну говорю же, разница в терминологии, что тут обсуждать.


                        • RE: А это от gcc, !*! Арлекин, 08:48 , 06-Сен-02 (21)
                          Ерничаем ? Это я насчет тайны. Какой смысл забивать форум двухэкранными листингами? Если я захочу что-то подправить или подменить я и так это сделаю. Если ты хочешь посмотреть на спарковский ассемблер могу тебе его описание в пдф выслать. Но не суть.
                          Значит так:
                          - с оптимизатором гнутый и в самом деле делает одинаковый код.
                          - спарк делает одинаковый на -О4 и -О5 (что там за варианты оптимизации не помню).
                          К сожалению (моему) я, видимо, избалован хорошей техникой, ибо оптимизаторами вообще не пользуюсь. Правда дебуг отключаю ! ))
                          ЗЫЖ Ораклячий OCI (мне именно с ним плотно приходится иметь дело последние годы) как-то странно относится к оптимизации, требуя оптимизировать все, кроме ЕГО файлов. У них, как обычно, либо кривой код, либо явная адресация на асме... Не люблю я их, как можно заметить...

                          Завязываем на том что ты прав.




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру