Zrozumienie INADDR_ANY do programowania gniazd

86

Próbuję zaprogramować kilka gniazd, więc po stronie serwera używam htonl(INADDR_ANY). O ile zrozumiałem, wydaje mi się, że ta funkcja generuje losowe IP (czy mam rację?). W rzeczywistości chcę powiązać moje gniazdo z moim localhost. Ale jeśli to uruchomię

Otrzymuję 0 jako wartość zwracaną. Czy ktoś mógłby przynieść jakieś wyjaśnienie?

epsilones
źródło
10
… Używam htonl(INADDR_ANY). Dokument mówi, że ta funkcja generuje losowe IP… ” To nie jest poprawne. Które dokumenty ci to mówią?
alk
1
@alk, właściwie wprowadzam w błąd: czytałem jakiś plik pdf, który uważałem za oficjalną dokumentację.
Edytuję

Odpowiedzi:

137
  1. bind()od INADDR_ANYrobi NIE „wygenerować losowy IP”. To wiąże się gniazdo do wszystkich dostępnych interfejsów .

  2. W przypadku serwera zazwyczaj chcesz powiązać wszystkie interfejsy - nie tylko „localhost”.

  3. Jeśli chcesz powiązać swoje gniazdo tylko z lokalnym hostem, składnia byłaby następująca my_sockaddress.sin_addr.s_addr = inet_addr("127.0.0.1");, a następnie call bind(my_socket, (SOCKADDR *) &my_sockaddr, ...).

  4. Tak się składa, że INADDR_ANYjest stałą równą zeru:

    http://www.castaglia.org/proftpd/doc/devel-guide/src/include/inet.h.html

  5. Jeśli jeszcze go nie znasz, zachęcam do zapoznania się z przewodnikiem Beej po programowaniu gniazd:

    http://beej.us/guide/bgnet/

Ponieważ ludzie nadal to czytają, dodatkowa uwaga:

man (7) ip :

Gdy proces chce otrzymywać nowe przychodzące pakiety lub połączenia, powinien powiązać gniazdo z adresem interfejsu lokalnego za pomocą funkcji bind (2) .

W takim przypadku tylko jedno gniazdo IP może być powiązane z dowolną parą lokalną (adres, port). Gdy INADDR_ANY zostanie podana w wywołaniu wiązania, gniazdo zostanie powiązane ze wszystkimi lokalnymi interfejsami.

Kiedy nasłuchiwanie (2) jest wywoływane na niezwiązanym gnieździe, gniazdo jest automatycznie wiązane z losowym wolnym portem z adresem lokalnym ustawionym na INADDR_ANY.

Gdy connect (2) jest wywoływany na niezwiązanym gnieździe, gniazdo jest automatycznie przypisywane do losowego wolnego portu lub do użytecznego portu współdzielonego z adresem lokalnym ustawionym na INADDR_ANY ...

Istnieje kilka adresów specjalnych: INADDR_LOOPBACK (127.0.0.1) zawsze odwołuje się do lokalnego hosta za pośrednictwem urządzenia zwrotnego; INADDR_ANY (0.0.0.0) oznacza dowolny adres do powiązania ...

Również:

bind () - Powiąż nazwę z gniazdem :

Jeśli pole (sin_addr.s_addr) jest ustawione na stałą INADDR_ANY, zgodnie z definicją w netinet / in.h, wywołujący żąda powiązania gniazda ze wszystkimi interfejsami sieciowymi na hoście. Następnie pakiety UDP i połączenia TCP ze wszystkich interfejsów (które pasują do powiązanej nazwy) są kierowane do aplikacji. Jest to ważne, gdy serwer oferuje usługę w wielu sieciach. Pozostawiając nieokreślony adres, serwer może akceptować wszystkie pakiety UDP i żądania połączeń TCP wysyłane do jego portu, niezależnie od interfejsu sieciowego, do którego przyszły żądania.

paulsm4
źródło
4
Nie oznacza „powiąż ze wszystkimi interfejsami”. Gdyby to zrobił, wynik netstat byłby inny. Oznacza to „słuchaj w dowolnym interfejsie”.
user207421
7
Cytując powyższy odsyłacz: "Kiedy INADDR_ANY jest określony w wywołaniu bind, gniazdo zostanie powiązane ze wszystkimi lokalnymi interfejsami." Z innego łącza: Wartość „INADDR_ANY” oznacza, że ​​będziemy wiązać się z każdym / wszystkimi adresami IP, które aktualnie posiada lokalny komputer . Ale tak - wiele implementacji zostanie przypisanych do pierwszego interfejsu (nie „wszystkie”). Ale w przypadku jednego komputera z jedną kartą sieciową różnica jest akademicka. Dzięki INADDR_ANY klient może łączyć się z dowolnym / wszystkimi adresami IP (np. Zarówno 192.168.1.2, jak i 127.0.0.1).
paulsm4
6
Przepraszam, jeśli to głupie pytanie, ale czy interfejs oznacza połączenie bezprzewodowe, Ethernet itp.?
mrQWERTY
3
@ laike9m Powiążesz 127.0.0.1, jeśli chcesz mieć możliwość połączenia się z gniazdem tylko z lokalnego komputera. Istnieją przypadki użycia, gdy usługa oferowana przez gniazdo jest przeznaczona do użycia tylko przez inny proces, który jest lokalny dla maszyny.
dgnuff
2
@ paulsm4 W 3, czy nie możesz użyć INADDR_LOOPBACKzamiast inet_addr("127.0.0.1")?
John Strood
63

INADDR_ANYjest używany, gdy nie musisz wiązać gniazda z określonym adresem IP. Gdy używasz tej wartości jako adresu podczas wywoływania bind(), gniazdo akceptuje połączenia ze wszystkimi adresami IP maszyny.

Barmar
źródło
8

Aby powiązać gniazdo z hostem lokalnym , przed wywołaniem funkcji bind należy odpowiednio ustawić pole sin_addr.s_addr struktury sockaddr_in. Odpowiednią wartość można uzyskać przez

lub przez

MichaelGoren
źródło
4

INADDR_ANYinstruuje nasłuchujące gniazdo, aby powiązało się ze wszystkimi dostępnymi interfejsami. To to samo, co próba nawiązania połączenia inet_addr("0.0.0.0"). Dla kompletności wspomnę również, że istnieje również IN6ADDR_ANY_INIT dla IPv6 i jest to to samo, co próba połączenia się z ::adresem dla gniazda IPv6.

Należy również pamiętać, że po powiązaniu gniazda IPv6 z IN6ADDR_ANY_INITgniazdem zostanie on powiązany ze wszystkimi interfejsami IPv6 i powinien być w stanie akceptować połączenia od klientów IPv4 (chociaż adresy mapowane na IPv6).

Pavel P.
źródło
2

INADDR_ANY to stała o wartości 0. będzie to używane tylko wtedy, gdy chcesz łączyć się ze wszystkich aktywnych portów, których nie obchodzi ip-add. więc jeśli chcesz podłączyć jakiś konkretny adres IP, powinieneś wspomnieć o tym jako my_sockaddress.sin_addr.s_addr = inet_addr ("192.168.78.2")

vivek
źródło