The OpenNET Project / Index page

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

форумы  помощь  поиск  регистрация  майллист  ВХОД  слежка  RSS
"Fork & Socket"
Вариант для распечатки  
Пред. тема | След. тема 
Форумы Программирование под UNIX (Public)
Изначальное сообщение [Проследить за развитием треда]

"Fork & Socket" 
Сообщение от Sergey emailИскать по авторуВ закладки(??) on 17-Ноя-05, 15:17  (MSK)
Hi ALL!

Есть две реализации запуска демона. Основное различие состоит в том, что в первой версии я сначала форкаю новый процесс, а затем создаю сокеты, во втором наоборот (сначала сокеты, а затем fork). В первом варианте все работает как нужно, во втором проблемы. Функция select в MainLoop постоянно возвращает 2, что указывает на наличие данных в двух сокетах (я использую UNIX сокет и TCP), хотя реально ничего еще нет. Я подозреваю, что проблема именно в последовательности вызова fork и socket. У меня закрытие сокетов сделано в деструкторе, поэтому после завершения главного процесса выполняется закрытие его сокетов. Не может ли быть так, что информация о сокетах не копируется, и при закрытии сокетов из главного процесса, они перестают быть доступны из порожденного?
Для меня второй вариант предпочтительней, т.к. в первом случае я не могу в скрипте запуска отследить запущен ли демон в действительности, если ошибки  возникли на этапе создания сокетов и объекта TDataInterface. В данном случае скрипт получает код возврата EXIT_SUCCESS при завершении главного процесса.

Как поступить, чтобы и волки были сыти и овцы целы?

Заранее благодарю за ответы!

Версия 1:

int Server::TServerApplication::Run(int _argc, char ** _argv)
{
// проверяем наличие обязательных параметров в коммандной строке
  if(_argc < 2 || _argv == 0)
  {
    char *fileName = strrchr(_argv[0], '/');

    if(fileName == NULL)
      fileName = _argv[0];
    else
      fileName++;

    Usage(fileName);
    return EXIT_FAILURE;
  }
  else
    if(!ParseCMD(_argc, _argv))
      return EXIT_FAILURE;

  // стартуем как демон                
  if(startAsDaemon)
  {
   if(!errorFile.is_open())
  {
     cerr << "Не определен параметр ERROR_FILE или произошла ошибка при открытии файла\n";
     return EXIT_FAILURE;
  }
  
   if(!logFile.is_open())
  {
     cerr << "Не определен параметр LOG_FILE или произошла ошибка при открытии файла\n";
     return EXIT_FAILURE;
  }
    
// переход на корневой раздел,
    chdir("/");
            
    // создаем копию процесса и завершаем родительский процесс
    if((pid = fork()))
      return EXIT_SUCCESS;
                                                                          
    // отрываемся от управляющего терминала
    setsid();
  }

  // устанавливаем обработчик handler на некоторые сигналы
  for(int j = 1; j < 32; j++)
    switch(j)
    {
      // по стандарту POSIX некоторые сигналы желательно обрабатывать всегда (не игнорировать)
      // назначим для этих сигналов обработчик по умолчанию
      case SIGFPE:
      case SIGILL:
      case SIGSEGV:
        sigset(j, SIG_DFL);
        break;
                                    
      default:
        sigset(j, handler);
    }

  { // сохраняем PID в файл
    ofstream pid_file(pidFile.c_str(), ios::out);

    if(pid_file.is_open())
    {
      pid_file << getpid();
      pid_file.close();
    }
  }

  // перенаправляем потоки в режиме демона
  if(startAsDaemon)
  {
    cerr.rdbuf(errorFile.rdbuf());
    cout.rdbuf(logFile.rdbuf());  
  }

try
  {
    int rc;
    factory = new TThreadFactory(this);
// загружаем данные из БД
dataIFACE = new TDataInterface(this, true);
    sock = new TSocket(PF_UNIX, SOCK_STREAM);

    // проверяем статус создания UNIX сокета
    if(sock->Good())
    {
      // присваиваем имя сокету и делаем сокет слушающим
      if((rc = sock->Bind(socketName.c_str())) < 0 || (!rc && sock->Listen() < 0))
        return EXIT_FAILURE;
    }
    else
      return EXIT_FAILURE;

    tcp_sock = new TSocket(PF_INET, SOCK_STREAM);

    // проверяем статус создания TCP сокета
    if(tcp_sock->Good())
    {
     rc = 1;
     setsockopt(tcp_sock->SID(), SOL_SOCKET, SO_REUSEADDR, &rc, sizeof(rc));
    
      // присваиваем имя сокету и делаем сокет слушающим
      if((rc = tcp_sock->Bind(serverName.c_str(), serverPort)) < 0 || (!rc && tcp_sock->Listen() < 0))
        return EXIT_FAILURE;
    }
    else
      return EXIT_FAILURE;
  }
catch(int) // ошибка создания TDataInterface
{
return EXIT_FAILURE;
}
  catch(std::bad_alloc)
  {
PrintCurrentTime();
    cerr << "TServerApplication::Run(): Ошибка выделения памяти\n";
    return EXIT_FAILURE;
  }
  
PrintCurrentTime(cout);
cout << "Сервер успешно стартовал\n\n";
  // запускаем главный цикл приложения
  return MainLoop();
}


Версия 2:

int Server::TServerApplication::Run(int _argc, char ** _argv)
{
  // проверяем наличие обязательных параметров в коммандной строке
  if(_argc < 2 || _argv == 0)
  {
    char *fileName = strrchr(_argv[0], '/');

    if(fileName == NULL)
      fileName = _argv[0];
    else
      fileName++;

    Usage(fileName);
    return EXIT_FAILURE;
  }
  else
    if(!ParseCMD(_argc, _argv))
      return EXIT_FAILURE;

  // стартуем как демон                
  if(startAsDaemon)
  {
    if(!errorFile.is_open())
    {
      cerr << "Не определен параметр ERROR_FILE или произошла ошибка при открытии файла\n";
      return EXIT_FAILURE;
    }
  
    if(!logFile.is_open())
    {
      cerr << "Не определен параметр LOG_FILE или произошла ошибка при открытии файла\n";
      return EXIT_FAILURE;
    }
    
    // перенаправляем потоки в режиме демона
    cerr.rdbuf(errorFile.rdbuf());
    cout.rdbuf(logFile.rdbuf());  
  }

  try
  {
    int rc;
    factory   = new TThreadFactory(this);
    // загружаем данные из БД
    dataIFACE = new TDataInterface(this, true);
    sock       = new TSocket(PF_UNIX, SOCK_STREAM);

    // проверяем статус создания UNIX сокета
    if(sock->Good())
    {
      // присваиваем имя сокету и делаем сокет слушающим
      if((rc = sock->Bind(socketName.c_str())) < 0 || (!rc && sock->Listen() < 0))
        return EXIT_FAILURE;
    }
    else
      return EXIT_FAILURE;

    tcp_sock = new TSocket(PF_INET, SOCK_STREAM);

    // проверяем статус создания TCP сокета
    if(tcp_sock->Good())
    {
      rc = 1;
      setsockopt(tcp_sock->SID(), SOL_SOCKET, SO_REUSEADDR, &rc, sizeof(rc));
        
      // присваиваем имя сокету и делаем сокет слушающим
      if((rc = tcp_sock->Bind(serverName.c_str(), serverPort)) < 0 || (!rc && tcp_sock->Listen() < 0))
        return EXIT_FAILURE;
    }
    else
      return EXIT_FAILURE;
  }
  catch(int) // ошибка создания TDataInterface
  {
    return EXIT_FAILURE;
  }
  catch(std::bad_alloc)
  {
    PrintCurrentTime();
    cerr << "TServerApplication::Run(): Ошибка выделения памяти\n";
    return EXIT_FAILURE;
  }
  
  PrintCurrentTime(cout);
  cout << "Сервер успешно стартовал\n\n";

  if(startAsDaemon)
  {
    // переход на корневой раздел,
    chdir("/");
            
    // создаем копию процесса и завершаем родительский процесс
    if((pid = fork()))
      return EXIT_SUCCESS;
                                                                          
    // отрываемся от управляющего терминала
    setsid();
  }

  // устанавливаем обработчик handler на некоторые сигналы
  for(int j = 1; j < 32; j++)
    switch(j)
    {
      // по стандарту POSIX некоторые сигналы желательно обрабатывать всегда (не игнорировать)
      // назначим для этих сигналов обработчик по умолчанию
      case SIGFPE:
      case SIGILL:
      case SIGSEGV:
        sigset(j, SIG_DFL);
        break;
                                    
      default:
        sigset(j, handler);
    }

  { // сохраняем PID в файл
    ofstream pid_file(pidFile.c_str(), ios::out);

    if(pid_file.is_open())
    {
      pid_file << getpid();
      pid_file.close();
    }
  }

  // запускаем главный цикл приложения
  return MainLoop();
}

  Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

 Оглавление

  • Fork & Socket, ACCA, 17:10 , 17-Ноя-05, (1)  
    • Fork & Socket, Sergey, 17:41 , 17-Ноя-05, (2)  
      • Fork & Socket, Sergey, 18:19 , 17-Ноя-05, (3)  

Сообщения по теме [Сортировка по времени, UBB]

1. "Fork & Socket" 
Сообщение от ACCA Искать по авторуВ закладки(ok) on 17-Ноя-05, 17:10  (MSK)
Обещаю про ДНК ничего не говорить.

>Есть две реализации запуска демона. Основное различие состоит в том, что в
>первой версии я сначала форкаю новый процесс, а затем создаю сокеты,
>во втором наоборот (сначала сокеты, а затем fork). В первом варианте

Теперь смотри, что ты сделал во втором случае: два процесса дерутся за единый системный ресурс - сокет. Как они себя будут вести - неизвестно, зависит от случайных факторов.

Дай каждому процессу свой сокет.

  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

2. "Fork & Socket" 
Сообщение от Sergey emailИскать по авторуВ закладки(??) on 17-Ноя-05, 17:41  (MSK)
>Обещаю про ДНК ничего не говорить.

Не понял.

>>Есть две реализации запуска демона. Основное различие состоит в том, что в
>>первой версии я сначала форкаю новый процесс, а затем создаю сокеты,
>>во втором наоборот (сначала сокеты, а затем fork). В первом варианте
>
>Теперь смотри, что ты сделал во втором случае: два процесса дерутся за
>единый системный ресурс - сокет. Как они себя будут вести -
>неизвестно, зависит от случайных факторов.
>
>Дай каждому процессу свой сокет.

Главному процессу вообще не нужен сокет, он закрывается после создания потомка. Ладно, попробую как-нибудь обойти создание сокета до форка.

  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

3. "Fork & Socket" 
Сообщение от Sergey emailИскать по авторуВ закладки(??) on 17-Ноя-05, 18:19  (MSK)
>>Обещаю про ДНК ничего не говорить.
>
>Не понял.
>
>>>Есть две реализации запуска демона. Основное различие состоит в том, что в
>>>первой версии я сначала форкаю новый процесс, а затем создаю сокеты,
>>>во втором наоборот (сначала сокеты, а затем fork). В первом варианте
>>
>>Теперь смотри, что ты сделал во втором случае: два процесса дерутся за
>>единый системный ресурс - сокет. Как они себя будут вести -
>>неизвестно, зависит от случайных факторов.
>>
>>Дай каждому процессу свой сокет.
>
>Главному процессу вообще не нужен сокет, он закрывается после создания потомка. Ладно,
>попробую как-нибудь обойти создание сокета до форка.

Придумал сделать pipe между parent'ом и child'ом и завершать parent process только после передачи статуса от child'а.


  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх


Архив | Удалить

Индекс форумов | Темы | Пред. тема | След. тема
Оцените тред (1=ужас, 5=супер)? [ 1 | 2 | 3 | 4 | 5 ]




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

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