INADDR_ANY
не имеет отношения к вашей проблеме.
Первый параметр getaddrinfo()
— это const char *
, указывающий IP-адрес или имя хоста. Но вместо этого INADDR_ANY
является целым числом. Единственная причина, по которой ваш код даже компилируется, заключается в том, что INADDR_ANY
определено как целочисленная константа 0, которая является единственной целочисленной константой, которую разрешено присваивать указателю. Итак, вы фактически передаете NULL первому параметру. Что хорошо в данной ситуации, так как это то, что вам в любом случае нужно.
Что вы не принимаете во внимание, так это то, что getaddrinfo()
возвращает связанный список адресов, который может содержать несколько адресов, особенно, если вы используете AF_UNSPEC
. Использование этого семейства сообщает getaddrinfo()
, что оно может возвращать адреса для как IPv4, так и IPv6. Но вы используете только первый адрес в списке, который как раз соответствует localhost
(127.0.0.1 в IPv4, ::1 в IPv6).
Для сервера вы должны создать и привязать отдельный прослушивающий сокет для каждого адреса в выходном списке. Это позволит вам привязаться ко всем адресам, которые соответствуют критериям, которые вы передали getaddrinfo()
, например:
addrinfo hints = {};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
addrinfo* result;
if (getaddrinfo(NULL, "7777", &hints, &result) == 0)
{
for (addrinfo *addr = result; addr != NULL; addr = addr->ai_next)
{
SOCKET listenSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (listenSocket != INVALID_SOCKET)
{
bind(listenSocket, addr->ai_addr, (int)addr->ai_addrlen);
listen(listenSocket, ...);
// store listenSocket in a list for later use...
}
}
freeaddrinfo(result);
}
// use listening sockets as needed...
В качестве альтернативы, как Сэм Ви упомянул в комментариях, вы можете пропустить getaddrinfo()
, это не очень поможет вам в этой ситуации. Вы можете просто создать и связать 2 сокета напрямую, один для IPv4 и один для IPv6:
SOCKET listenSocket4 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket4 != INVALID_SOCKET)
{
sockaddr_in addr = {};
addr.sin_family = AF_INET;
addr.sin_port = htons(7777);
addr.sin_addr.s_addr = INADDR_ANY;
bind(listenSocket4, (sockaddr*) &addr, sizeof(addr));
listen(listenSocket4, ...);
}
SOCKET listenSocket6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket6 != INVALID_SOCKET)
{
sockaddr_in6 addr = {};
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(7777);
addr.sin6_addr = in6addr_any;
bind(listenSocket6, (sockaddr*) &addr, sizeof(addr));
listen(listenSocket6, ...);
}
// use listening sockets as needed...
Или лучше создайте и привяжите один двойной стек сокет, который поддерживает оба IPv4 и IPv6:
SOCKET listenSocket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket != INVALID_SOCKET)
{
BOOL off = FALSE;
setsockopt(listenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&off, sizeof(off));
sockaddr_in6 addr = {};
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(7777);
addr.sin6_addr = in6addr_any;
bind(listenSocket, (sockaddr*) &addr, sizeof(addr));
listen(listenSocket, ...);
}
// use listening socket as needed...
person
Remy Lebeau
schedule
08.10.2017
INADDR_ANY
имеет ожидаемый эффект, когда он передается в качестве параметра непосредственно вbind()
. Вы этого не делаете. Вы передаете это значение вgetaddrinfo()
. Это совсем другая история. Теперь, почему бы вам не изучить, чтоgetaddrinfo()
возвращает в этом случае, и не выяснить это самостоятельно. Если вы хотите принимать соединения с любого локального IP-адреса, вам не нуженgetaddrinfo()
. Избавьтесь от всего этого целиком и вызовитеbind()
напрямую. - person Sam Varshavchik   schedule 08.10.2017getaddrinfo()
вообще сработало? Вы не удосужились проверить возвращаемое значение. В соответствии с стандартом POSIX: нулевое возвращаемое значение дляgetaddrinfo()
указывает на успешное завершение. ; ненулевое возвращаемое значение указывает на сбой. Возможные значения ошибок перечислены в разделе ОШИБКИ. - person Andrew Henle   schedule 08.10.2017getaddrinfo
может возвращать несколько адресов; и вам также нужноfreeaddrinfo(result)
, но вы всегда связываете только первый. - person Antti Haapala   schedule 08.10.2017getaddrinfo
и напрямую использоватьbind()
? например, если да, то как мы узнаем адрес для привязки? - person Crystina   schedule 24.09.2020bind()
. Дополнительную информацию см. в документацииbind()
. Вы указываетеINADDR_ANY
в качестве адреса для привязки. Конец. - person Sam Varshavchik   schedule 24.09.2020