Понимание INADDR_ANY для программирования сокетов
Я пытаюсь запрограммировать несколько сокетов и поэтому на стороне сервера использую htonl(INADDR_ANY)
, Насколько я понял, мне кажется, что эта функция генерирует случайный IP (я прав?). На самом деле, я хочу связать мою розетку с моим localhost
, Но если я запущу это
printf("%d",htonl(INADDR_ANY));
Я получаю 0 в качестве возвращаемого значения. Может ли кто-нибудь привести какое-то объяснение?
7 ответов
bind()
изINADDR_ANY
НЕ "генерирует случайный IP". Он связывает сокет со всеми доступными интерфейсами.Для сервера вы обычно хотите связать все интерфейсы, а не только "localhost".
Если вы хотите привязать свой сокет только к localhost, синтаксис будет
my_sockaddress.sin_addr.s_addr = inet_addr("127.0.0.1");
затем позвонитеbind(my_socket, (SOCKADDR *) &my_sockaddr, ...)
,Как это происходит,
INADDR_ANY
константа, которая равна "нулю":http://www.castaglia.org/proftpd/doc/devel-guide/src/include/inet.h.html
# define INADDR_ANY ((unsigned long int) 0x00000000) ... # define INADDR_NONE 0xffffffff ... # define INPORT_ANY 0 ...
Если вы еще не знакомы с ним, я призываю вас ознакомиться с Руководством Beej по программированию сокетов:
Так как люди все еще читают это, дополнительное примечание:
Когда процесс хочет получить новые входящие пакеты или соединения, он должен связать сокет с адресом локального интерфейса, используя bind (2).
В этом случае только один IP-сокет может быть связан с любой данной локальной парой (адрес, порт). Если в вызове bind указано 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-соединения, сделанные для его порта, независимо от сетевого интерфейса, на который поступили запросы.
INADDR_ANY
используется, когда вам не нужно привязывать сокет к определенному IP. Когда вы используете это значение в качестве адреса при звонке bind()
, сокет принимает соединения со всеми IP-адресами машины.
Чтобы связать сокет с локальным хостом, перед вызовом функции связывания поле sin_addr.s_addr структуры sockaddr_in должно быть правильно установлено. Правильное значение может быть получено либо
my_sockaddress.sin_addr.s_addr = inet_addr("127.0.0.1")
или
my_sockaddress.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
INADDR_ANY
дает команду прослушивающему сокету связываться со всеми доступными интерфейсами. Это то же самое, что пытаться связать inet_addr("0.0.0.0")
, Для полноты я также упомяну, что для IPv6 также есть IN6ADDR_ANY_INIT, и это то же самое, что пытаться связать ::
адрес для сокета IPv6.
#include <netinet/in.h>
struct in6_addr addr = IN6ADDR_ANY_INIT;
Также обратите внимание, что при привязке сокета IPv6 к IN6ADDR_ANY_INIT
Ваш сокет будет привязан ко всем интерфейсам IPv6 и должен иметь возможность принимать соединения от клиентов IPv4 (хотя адреса, сопоставленные с IPv6).
Когда у вас есть сервер, вы создаете сокет, а затем привязываете его к IP-адресу и порту, что дает сокету уникальный способ идентификации на основе уникального типа сокета, семейства адресов, IP-адреса и порта. Затем вы listen(), чтобы установить сокет в режим сервера, а затем вы выполняете accept(), который ожидает соединения, которое будет иметь входящие пакеты с целевыми параметрами, которые вызывают постановку пакетов в очередь на этом сокете.
Когда у вас есть клиент, вы создаете сокет, а затем подключаете () сокет к удаленному IP-адресу и порту, который также привяжет 0.0.0.0 и случайный неиспользуемый эфемерный порт к сокету, если он еще не был привязан. к IP-адресу и порту с помощью привязки (INADDR_ANY, 0). connect() возвращается при подключении и использует IP-адрес и порт в качестве исходного адреса в исходящих пакетах, где 0.0.0.0 всегда заменяется ОС на текущий внутренний IP-адрес, а затем вы используете sendall для отправки данных приложения.
INADDR_ANY быстрее, чем программное получение текущего внутреннего IP-адреса компьютера, который может измениться в любой момент, и пакеты больше не будут приниматься на порт, но они все равно будут приниматься на 0.0.0.0, потому что это любой адрес.
Обратите внимание, что сокет может быть привязан к 0.0.0.0, но не к порту 0, потому что это подстановочный знак, который заставляет его назначать сокету случайный эфемерный порт, поэтому, когда вы используете привязку (INADDR_ANY, 0), он привязывается к 0.0.0.0 и случайный эфемерный порт.
INADDR_ANY - это константа, которая содержит 0 в значении. это будет использоваться только тогда, когда вы хотите подключиться со всех активных портов, которые вам не нужны для ip-add. поэтому, если вы хотите подключить какой-либо конкретный ip, вы должны упомянуть как my_sockaddress.sin_addr.s_addr = inet_addr("192.168.78.2")
#include <arpa/inet.h>
.
.
tcpsock.sin_addr.s_addr = inet_addr("192.168.1.2")
работал на меня