getockopt() возвращает EINPROGRESS в неблокирующем потоке connect()+select()

Обновление:

Виноват. Я получаю сообщение об ошибке ECONNREFUSED, а не EINPROGRESS. После проверки переменной error я обнаружил, что она больше 0, и напечатал errno вместо error. Конечно, errno это EINPROGRESS, потому что его значение не изменилось с момента вызова connect().

Ответ на вопрос. Спасибо, ребята.

Я использую тот же фрагмент кода, что и в примере Stevens Network Programming UNIX, не блокирующего соединение():

  1. Настройка сокета на неблокирующий
  2. Инициировать неблокирующее соединение ()
  3. Проверка на немедленное завершение
  4. Вызовите select() с тайм-аутом и дождитесь готовности чтения или записи
  5. Когда select() возвращает значение больше 0, выполните getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, &len).

Я получаю сообщение об ошибке EINPROGRESS. Код выполняется на сервере rhel5.

Любые идеи, почему я получаю эту ошибку?

Фрагмент кода:

 flags = fcntl(sockfd, F_GETFL, 0);
 fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

 if ((retVal = connect(sockfd, saptr, salen)) < 0)
     if (errno != EINPROGRESS)
  return (-1);

 if (retVal == 0)
 {
     // restore file status flags
     fcntl(sockfd, F_SETFL, flags);  
     return 0;
 }

 FD_ZERO(&rset);
 FD_SET(sockfd, &rset);
 wset = rset;
 tval.tv_sec = nsec;
 tval.tv_usec = 0;

 if ((retVal = select(sockfd + 1, &rset, &wset, NULL, &tval)) == 0) 
 {
     // timeout
     close(sockfd);          
     errno = ETIMEDOUT;
     return (-1);
 }

 if (retVal < 0) 
 {
     // select() failed
     return (-1);
 }

 if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) 
 {
     len = sizeof(error);
     error = 0;
     if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
  return (-1);     

     if (error > 0) //<<<<< error == EINPROGRESS >>>
     { 
  close(sockfd);
  errno = error;
  return (-1);
     }
 } 
 else
 {
     return (-1);
 }

 // restore file status flags
 fcntl(sockfd, F_SETFL, flags);  

person tonymontana    schedule 08.07.2009    source источник
comment
Это звучит правильно. Возможно, вам следует опубликовать соответствующий фрагмент кода.   -  person Duck    schedule 08.07.2009
comment
Что неожиданного? Неблокирующий connect будет продолжать сообщать EINPROGRESS, пока соединение не будет установлено. Это задокументировано на справочной странице для connect.   -  person ephemient    schedule 08.07.2009
comment
@ephemient: последующие вызовы для подключения будут возвращаться УЖЕ, не так ли?   -  person Aditya Sehgal    schedule 08.07.2009
comment
@ephemient: это действительно документ, но здесь это не так. Вот почему присутствует вызов select(). Он ожидает, пока соединение все еще находится в состоянии EINPROGRESS. Как только select() возвращает значение, это означает одно из следующих событий: (a) соединение успешно завершено (b) соединение обнаружило ошибку (c) время ожидания select() истекло и возвращено 0 (d) select() не выполнено и возвращено -1   -  person tonymontana    schedule 08.07.2009


Ответы (3)


Черт... Я сдаюсь. Я пытался и пытался, но не смог найти проблему с вашим кодом. Итак, все, что я предлагаю, это некоторые предположения и гипотезы.

  • Используйте FD_COPY, чтобы скопировать rset в wset.

  • Можете ли вы сделать getsockopt при сбое первого подключения. Я подозреваю, что Select возвращает 0, и из-за вышеизложенного каким-то образом установлен ваш набор writefd, и выполнение getockopt возвращает вам устаревшую ошибку из предыдущего подключения. IMO, последующее соединение должно возвращаться УЖЕ (хотя это может зависеть от платформы)

Пожалуйста, сделайте то же самое (и поставьте мне минус, если я ошибаюсь в использовании FD_COPY) и поделитесь результатами.

person Aditya Sehgal    schedule 08.07.2009
comment
Адитья, я нашел проблему и отредактировал свой первоначальный вопрос с описанием проблемы. Это мое плохо. Я напечатал неправильное значение внутри блока if (ошибка › 0) (соответствующий printf отсутствует во фрагменте кода). Спасибо большое за помощь. - person tonymontana; 08.07.2009

EINPROGRESS указывает, что неблокирующий метод connect() все еще... выполняется.

Поэтому я хотел бы спросить: вы проверяете, что после возврата select() файловый дескриптор connect() все еще установлен в writefds fd_set? Если это не так, то это означает, что select() вернулся по какой-то другой причине.

person caf    schedule 08.07.2009

Значение выбора больше нуля не указывает на какую-либо ошибку... это количество сокетов, которые соответствуют критериям оператора выбора. select вернет -1 в случае ошибки.

Мне непонятно, допустим ли вызов getsocktopt с SO_ERROR; вам, вероятно, лучше всего придерживаться проверки на наличие ошибок каждый раз, когда вы используете сокет (что, я думаю, вы все равно делаете). Если выбор не терпит неудачу, все в порядке.

person Chris Arguin    schedule 08.07.2009
comment
С select() проблем нет. здесь делается вызов getsockopt() для проверки успешности неблокирующего подключения(). В моем случае это не так. - person tonymontana; 08.07.2009