С исходным кодом есть две проблемы:
- Член ai_addr указывает на sockaddr, а не на struct in_addr, поэтому приведение его так всегда приведет к неверным результатам.
- Если вы не передадите подсказку, отличную от NULL, и если элемент af_family имеет значение AF_INET, вы не можете ожидать, что все возвращаемые адреса будут IPv4 (тип struct sockaddr_in).Таким образом, вы можете предоставить подсказки для указания IPv4 или проверить член af_family получающихся структур addrinfo.
Одна вещь, которую я обычно вижу по крайней мере в системах Linux, состоит в том, что getaddrinfo для localhost обычно возвращает IPv6 ::Сначала адрес 1.
По напечатанным адресам я могу сказать, что вы работаете в ОС, которая включает в себя длину sockaddrs в структуре.Например, определение struct sockaddr в OS X выглядит следующим образом:
struct sockaddr {
__uint8_t sa_len; /* total length */
sa_family_t sa_family; /* [XSI] address family */
char sa_data[14]; /* [XSI] addr value (actually larger) */
};
Как для struct sockaddr_in, так и для sockaddr_in6 самый следующий член после sa_family - это порт, который всегда составляет два байта.Поэтому, когда вы приведете любую из этих структур к структуре in_addr, вы получите адрес sa_len.sa_family.0.0 (при условии, что вы не предоставляете порт для getaddrinfo - если вы предоставите порт, 0.0 будет заменен байтом портов.значения).
Итак, информация gettaddr возвращает вам два IPv6-адреса: 28.30.0.0 - sizeof struct sockaddr_in6 = 28 и af_family = 30
и два IPv4-адреса: 16.2.0.0 - sizeof struct sockaddr_in= 16 и af_family = 2
Чтобы сделать это правильно, вы можете сделать то, что сказал другой ответ, и использовать getnameinfo.Однако использование inet_ntop (не inet_ntoa) может быть одинаково хорошим.
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h> /* for memset */
int main()
{
char addr_buf[64];
struct addrinfo* feed_server = NULL;
memset(addr_buf, 0, sizeof(addr_buf));
getaddrinfo("localhost", NULL, NULL, &feed_server);
struct addrinfo *res;
for(res = feed_server; res != NULL; res = res->ai_next)
{
if ( res->ai_family == AF_INET )
{
inet_ntop(AF_INET, &((struct sockaddr_in *)res->ai_addr)->sin_addr, addr_buf, sizeof(addr_buf));
}
else
{
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, addr_buf, sizeof(addr_buf));
}
printf("hostname: %s\n", addr_buf);
}
return 0;
}
`` `