Мой сервер не будет принимать соединения при работе в фоновом режиме - PullRequest
1 голос
/ 15 января 2012

Я написал простой сервер на C. Он отвечает на соединения через порт 8888. Он прекрасно работает ... пока я не попытаюсь запустить его как фоновый процесс.

Когда я запускаю его как

$ ./server

А затем попытка соединения с клиентом работает нормально. Когда я пытаюсь запустить его как:

$ ./server &

Или если я запустлю его как

$ ./server 

А затем отсоедините его с помощью CTRL + z и попытайтесь подключиться к клиенту. Я получаю

Connection Refused

Кто-нибудь сталкивался с этой проблемой раньше? Я был бы очень признателен за решение.

Вот код, соответствующий запросу accept( ):

  char remoteIP[ INET6_ADDRSTRLEN ];
  int yes=1;    /* for setsockopt() SO_REUSEADDR, below */
  int i, rv;
  struct addrinfo hints, *ai, *p;

  FD_ZERO( &master );  /* clear the master and temp sets */
  FD_ZERO( &read_fds );

  /* get us a socket and bind it */
  memset( &hints, 0, sizeof hints );
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  if ( ( rv = getaddrinfo( NULL, URL_PORT, &hints, &ai ) ) != 0 )
  {
    /* fprintf( stderr, "selectserver: %s\n", gai_strerror( rv ) ); */
    exit( 1 );
  }

  /* printf( "Listening on port %s for URLs...\n", URL_PORT ); */
  for( p = ai; p != NULL; p = p->ai_next )
  {
    listener = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
    if ( listener < 0 )
    {
      continue;
    }

    /* lose the pesky "address already in use" error message */
    setsockopt( listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof( int ) );
    if ( bind( listener, p->ai_addr, p->ai_addrlen) < 0 )
    {
      close( listener );
      continue;
    }
    break;
  }

  /* if we got here, it means we didn't get bound */
  if ( p == NULL )
  {
    /* fprintf( stderr, "selectserver: failed to bind\n" ); */
    exit( 2 );
  }

  freeaddrinfo( ai ); /* all done with this */

  /* listen */
  if ( listen( listener, 10 ) == -1 )
  {
    perror( "listen" );
    exit( 3 );
  }

  /* add the listener to the master set */
  FD_SET( listener, &master );

  /* keep track of the biggest file descriptor */
  fdmax = listener; /* so far, it's this one */

  /* main loop */
  for( ; ; ) {


    for( i = 0; i <= fdmax; i++ )
    {
      if ( SOCKETS[ i ].in_progress )
      {
        if ( pthread_join( SOCKETS[ i ].thread, NULL ) != 0 )
        {
          /* fprintf( stderr, "Error terminating thread %i\n", i ); */
        }
        else
        {
          SOCKETS[ i ].in_progress = FALSE;
        }
      }
    }

    read_fds = master; /* copy it */

    if ( select( fdmax + 1, &read_fds, NULL, NULL, NULL ) == -1 )
    {
      perror( "select" );
      exit(4);
    }

    /* run through the existing connections looking for data to read */
    for( i = 0; i <= fdmax; i++ ) {

      if ( FD_ISSET( i, &read_fds ) && SOCKETS[ i ].in_progress == FALSE )
      {
        /* we got one!! */
        if ( i == listener )
        {
          /* handle new connections */
          addrlen = sizeof remoteaddr;
          newfd = accept( listener, ( struct sockaddr * ) &remoteaddr, &addrlen );
          if ( newfd == -1 )
          {
            perror( "accept" );
          }
          else
          {
            FD_SET( newfd, &master ); /* add to master set */

            if ( newfd > fdmax )
            {  /* keep track of the max */
              fdmax = newfd;
            }

            /*
            printf( 
              "selectserver: new connection from %s on socket %d\n",
              inet_ntop( remoteaddr.ss_family, get_in_addr( ( struct sockaddr* ) &remoteaddr ), remoteIP, INET6_ADDRSTRLEN ), newfd );
            */
          }
        }

1 Ответ

4 голосов
/ 15 января 2012

Ваш процесс читает с управляющего терминала или записывает его и, следовательно, останавливается SIGTTIN или SIGTTOU, когда вы запускаете его в фоновом режиме с &.

Соответствующим отрывком из страницы руководства bash * 1005.*:

Только процессы переднего плана могут читать или записывать в терминал.Фоновые процессы, которые пытаются прочитать (записать) на терминал, отправляют сигнал SIGTTIN (SIGTTOU) драйвером терминала, который, если не перехвачен, приостанавливает процесс.

Отправка SIGTTOU контролируетсяфлагом, который по умолчанию выключен, поэтому ваша проблема, скорее всего, вызвана чтением с управляющего терминала.Если вы хотите запретить фоновым процессам выполнять запись в терминал (т. Е. Повторно разрешить отправку SIGTTOU процессам, пытающимся выполнить фоновую запись), используйте эту команду:

stty tostop

Вы можете вернуться к поведению по умолчаниюс помощью:

stty -tostop

Когда вы нажимаете Ctrl + Z, вы запускаете процесс SIGTSTP.Расположение этого сигнала по умолчанию также останавливает процесс.Если вы хотите, чтобы процесс продолжался в фоновом режиме, используйте эту команду:

bg %1

Обратите внимание, что в вашем случае номер задания может отличаться.Проверьте с помощью команды job.

Обратите внимание, что в отличие от SIGSTOP эти три сигнала могут обрабатываться или игнорироваться вашим процессом, если вам не нравится поведение.Системные вызовы чтения / записи будут возвращать EINTR вместо блокировки.

...