Понимание INADDR_ANY для программирования сокетов

86

Я пытаюсь запрограммировать несколько сокетов, поэтому на стороне сервера я использую htonl(INADDR_ANY). Насколько я понял, мне кажется, что эта функция генерирует случайный IP (я прав?). Фактически, я хочу связать свой сокет с моим localhost. Но если я запустил это

Я получаю 0 как возвращаемое значение. Может кто-нибудь дать объяснение?

эпсилоны
источник
10
« ... Я использую htonl(INADDR_ANY). В документе сказано, что эта функция генерирует случайный IP ... » Это неверно. Какие документы вам об этом говорят?
alk
1
@alk, на самом деле я ввожу в заблуждение: я читал какой-то pdf, который, как мне показалось, был официальной документацией. Я редактирую свой пост сейчас
эпсилонес

Ответы:

137
  1. bind()из INADDR_ANYдействительно НЕ «генерировать случайные IP». Он связывает сокет со всеми доступными интерфейсами .

  2. Для сервера обычно требуется привязка ко всем интерфейсам, а не только к «localhost».

  3. Если вы хотите привязать свой сокет только к localhost, синтаксис будет следующим my_sockaddress.sin_addr.s_addr = inet_addr("127.0.0.1");: call bind(my_socket, (SOCKADDR *) &my_sockaddr, ...).

  4. Как оказалось, INADDR_ANYэто константа, которая оказывается равной нулю:

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

  5. Если вы еще не знакомы с ним, я настоятельно рекомендую вам ознакомиться с Руководством Beej по программированию сокетов:

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

Поскольку люди все еще читают это, дополнительное примечание:

человек (7) ip :

Когда процесс хочет получить новые входящие пакеты или соединения, он должен привязать сокет к адресу локального интерфейса с помощью bind (2) .

В этом случае только один IP-сокет может быть привязан к любой данной локальной паре (адрес, порт). Когда INADDR_ANY указан в вызове привязки, сокет будет привязан ко всем локальным интерфейсам.

Когда listen (2) вызывается для несвязанного сокета, сокет автоматически привязывается к случайному свободному порту с локальным адресом, установленным на INADDR_ANY.

Когда connect (2) вызывается для несвязанного сокета, сокет автоматически привязывается к случайному свободному порту или к используемому общему порту с локальным адресом, установленным на INADDR_ANY ...

Есть несколько специальных адресов: INADDR_LOOPBACK (127.0.0.1) всегда обращается к локальному хосту через устройство обратной связи; INADDR_ANY (0.0.0.0) означает любой адрес для привязки ...

Также:

bind () - привязывает имя к сокету :

Если в поле (sin_addr.s_addr) задана константа INADDR_ANY, как определено в netinet / in.h, вызывающий запрос запрашивает привязку сокета ко всем сетевым интерфейсам на хосте. Впоследствии пакеты UDP и TCP-соединения со всех интерфейсов (которые соответствуют связанному имени) направляются в приложение. Это становится важным, когда сервер предлагает услугу нескольким сетям. Если адрес не указан, сервер может принимать все UDP-пакеты и запросы TCP-соединения, сделанные для его порта, независимо от сетевого интерфейса, на который поступили запросы.

paulsm4
источник
4
Это не означает «привязать ко всем интерфейсам». Если бы это было так, вывод netstat был бы другим. Это означает «слушать на любом интерфейсе».
user207421
7
Процитируем приведенную выше ссылку: «Когда в вызове привязки указан INADDR_ANY, сокет будет привязан ко всем локальным интерфейсам». По другой ссылке: значение «INADDR_ANY» означает, что мы будем выполнять привязку к любым / всем IP-адресам, которые в настоящее время есть у локального компьютера . Но да - многие реализации будут привязаны к первому интерфейсу (не «все»). Но для одного ПК с одной сетевой картой разница академическая. С INADDR_ANY клиент может подключаться к любому / всем IP (например, 192.168.1.2 и 127.0.0.1).
paulsm4
6
Извините, если это глупый вопрос, но означает ли интерфейс беспроводной, Ethernet и т. Д.?
mrQWERTY
3
@ laike9m Вы должны выполнить привязку к 127.0.0.1, если хотите иметь возможность подключаться к сокету только с локального компьютера. Для этого существуют варианты использования, когда услуга, предлагаемая сокетом, предназначена только для использования другим процессом, локальным для машины.
dgnuff
2
@ paulsm4 В 3 разве нельзя использовать INADDR_LOOPBACKвместо inet_addr("127.0.0.1")?
Джон Строуд
63

INADDR_ANYиспользуется, когда вам не нужно привязывать сокет к определенному IP. Когда вы используете это значение в качестве адреса при вызове bind(), сокет принимает соединения со всеми IP-адресами машины.

Barmar
источник
8

Чтобы связать сокет с localhost , перед вызовом функции связывания необходимо правильно установить поле sin_addr.s_addr структуры sockaddr_in. Правильное значение может быть получено либо

или по

Майкл Горен
источник
4

INADDR_ANYуказывает прослушивающему сокету привязаться ко всем доступным интерфейсам. Это то же самое, что пытаться привязаться к inet_addr("0.0.0.0"). Для полноты я также упомяну, что существует также IN6ADDR_ANY_INIT для IPv6, и это то же самое, что и попытка привязки к ::адресу для сокета IPv6.

Также обратите внимание, что когда вы привязываете сокет IPv6 к IN6ADDR_ANY_INITвашему сокету, он будет привязан ко всем интерфейсам IPv6 и также должен иметь возможность принимать соединения от клиентов IPv4 (хотя адреса с отображением IPv6).

Павел П.
источник
2

INADDR_ANY - это константа, значение которой равно 0. это будет использоваться только тогда, когда вы хотите подключиться со всех активных портов, которые вам не нужны, ip-add. поэтому, если вы хотите подключить какой-либо конкретный IP-адрес, вы должны указать, например, my_sockaddress.sin_addr.s_addr = inet_addr ("192.168.78.2")

вивек
источник