2013-02-20 4 views
1

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

int 
connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec) 
{ 
    int      flags, n, error; 
    socklen_t    len; 
    fd_set     rset, wset; 
    struct timeval tval; 

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

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

    /* Do whatever we want while the connect is taking place. */ 

    if (n == 0) 
      goto done;  /* connect completed immediately */ 

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

    if ((n = Select(sockfd+1, &rset, &wset, NULL, 
            nsec ? &tval : NULL)) == 0) { 
      close(sockfd);   /* timeout */ 
      errno = ETIMEDOUT; 
      return(-1); 
    } 

    if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) { 
      len = sizeof(error); 
      if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) 
        return(-1);      /* Solaris pending error */ 
    } else 
      err_quit("select error: sockfd not set"); 

done: 
    Fcntl(sockfd, F_SETFL, flags); /* restore file status flags */ 

    if (error) { 
      close(sockfd);   /* just in case */ 
      errno = error; 
      return(-1); 
    } 
    return(0); 
} 

Эта функция позволяет пользовательский тайм-аут подключения(). Если, в то время как блокировка в select(), ожидающая завершения соединения, получает сигнал, select() выходит с -1 (EINTR). На этом этапе тайм-аут select() не истек, соединение не удалось (т. Е. Целевой хост может быть отключен), но последующий getockopt() не возвращает ошибку.

Должно ли getsockopt() возвращать ошибку или должен ли код Стивенса проверять код возврата (и errno) select()?

В настоящее время при подключении к несуществующему хосту и прерываниям сигнала select() эта функция возвращает успех неправильно.

+1

Это, безусловно, должно проверить код возврата 'select'. Не делать этого, на мой взгляд, довольно большой надзор. –

+0

Выберите в своем примере капитал S, что означает, что он его завернул. Что находится в завершенной версии выбора? Я бы ожидал, что он поймает и обработает EINTR там, вот что я сделаю ... – Joe

+0

Джо, я думал, что слишком, но Select() просто добавляет печать ошибок. http://pastebin.com/Eua4vdZE – wilysloth

ответ

2

Я не уверен, что такое Select(). Я предполагаю, что это какая-то тонкая обертка вокруг select().

В большинстве случаев, когда select() терпит неудачу с EINTR, вы должны молча цикл и вызвать select() снова, возможно, после перерасчета тайм-аут, чтобы объяснить тот факт, что некоторое время истекло в предыдущем вызове select().

Этот случай не является исключением. select() должен находиться в цикле.

Смежные вопросы