2013-03-06 11 views
6

Mam gniazdo blokujące (przynajmniej wydaje się więc w następujący kod):connect() zwraca "Operacja teraz w toku" na gnieździe blokującym?

sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (sock < 0) { 
      ERROR("%s: error opening socket", __func__); 
      return (RESP_ERROR); 
    } 

    t.tv_sec = timeout; 
    t.tv_usec = 0; 

    int rf = fcntl(sock, F_GETFD); 
    ERROR("fcntl ret=%d, ret & O_NONBLOCK = %d", rf, rf & O_NONBLOCK); 

    if ((setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&t, sizeof (t)) < 0) 
     || (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&t, sizeof (t)))) { 
      strerror_r(errno, err, 254); 
      ERROR("%s: error on setsockopt -> %s", __func__, err); 
      close(sock); 
      return (RESP_ERROR); 
    } 

    rf = fcntl(sock, F_GETFD); 
    ERROR("after select fcntl ret=%d, ret & O_NONBLOCK = %d", rf, rf & O_NONBLOCK); 

    if (connect(sock, (struct sockaddr *)&dst, sizeof (dst)) != 0) { 
      strerror_r(errno, err, 254); 
      ERROR("%s: error on connect -> %s", __func__, err); 
      close(sock); 
      return (RESP_ERROR); 
    } 

A to z dziennika:

06 marca 10:42:04 TcpClient: fcntl ret = 0 RET & O_NONBLOCK = 0

06 marca 10:42:04 TcpClient: po wybraniu fcntl RET = 0 RET & O_NONBLOCK = 0

06 marca 10:42:14 TcpClient : authenticate: error on connect -> Działanie w toku

Wygląda na to, że jest to gniazdo blokujące, ale zwraca błąd typowy dla braku blokady? Linux to 2.6.18-308.el5. Jakieś pomysły?

+1

'timeout' ma jaką wartość? – alk

+0

Aby zweryfikować moją odpowiedź, chciałbym zrobić kilka testów. Dlatego chciałbym wiedzieć, jak 'dst' został zainicjowany przed przekazaniem go do' connect() '. Czy jesteś pewien, że jego członek 'sin_family' został poprawnie ustawiony? – alk

Odpowiedz

4

Jeśli timeout nie jest 0, połączenie z connect() przekroczy i zwróci. Dzieje się tak niezależnie od tego, czy nawiązano połączenie, czy nie.

Od momentu upłynięcia limitu czasu connect() zachowuje się tak, jakby był wywoływany na nieblokującym gnieździe.

Nawiązując tym przypadku (dosłownie z man connect i ignoruj ​​„natychmiast” poniżej)

EINPROGRESS

Gniazdo jest nonblocking a połączenie nie może być zakończone natychmiast. Możliwe jest wybranie (2) lub odpytywanie (2) do zakończenia przez wybranie gniazda do zapisu. Po zaznaczeniu (2) wskazuje na zdolność do puszczania, użyj getsockopt (2), aby odczytać opcję SO_ERROR na poziomie SOL_SOCKET, aby określić, czy connect() zakończyło się pomyślnie (SO_ERROR wynosi zero) lub bezskutecznie (SO_ERROR jest jednym ze zwykłych kodów błędów wymienionych tutaj, wyjaśnij - powód niepowodzenia).


BTW: Czy ktoś może potwierdzić to standardowe zachowanie, a do tego wyraźnie wspomniano gdzieś?

man 7 socket członkowskie (kursywa przeze mnie):

SO_RCVTIMEO i SO_SNDTIMEO

Określ odbiera lub wysyła limity czasu aż zgłoszenie błędu. [...] jeśli żadne dane nie zostały przesłane, a limit czasu został osiągnięty, to -1 jest zwracane z errno ustawionym na EAGAIN lub EWOULDBLOCK tak, jakby gniazdo było określone jako niezablokowane. [...] Przekroczenie limitu czasu ma wpływ tylko na wywołania systemowe, które wykonują operacje wejścia/wyjścia gniazda (np. Read (2), recvmsg (2), send (2), sendmsg (2)); limity czasu nie mają wpływu na select (2), ankiety (2), epoll_wait (2), itp

Żadne słowo dotyczące connect() więc jestem pewien, moja odpowiedź będzie trzymać.

+0

Pojawia się komunikat "Od momentu upływu limitu czasu funkcja connect() zachowuje się tak, jakby była wywoływana w niezapalającym gnieździe." to jest kluczowa część. Czy zamknięcie (skarpetka) zatrzyma tę operację? –

+1

Sure 'close()' invalides gniazda. Jednak system operacyjny może przez pewien czas trzymać rękę na adres: port. Aby zmienić adres: port przed wydaniem systemu operacyjnego, możesz określić opcję gniazda 'SO_REUSEADDR'. – alk

+0

Nie widzę powodu, dla którego ustawienie limitu czasu odczytu lub zapisu wpłynęłoby na connect(). Jedynym sposobem, w jaki mam świadomość przekroczenia limitu czasu, jest wykonanie go w trybie bez blokowania za pomocą select(). – EJP

0

Wypróbuj za pomocą "if ((connect (...)) < 0)". Być może w ogóle nie otrzymujesz błędu.

Powiązane problemy