getaddrinfo и IPv6
Я пытаюсь понять, что возвращает функция getaddrinfo:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
int main (int argc, char *argv[])
{
struct addrinfo *res = 0 ;
getaddrinfo("localhost", NULL ,NULL,&res);
printf("ai_flags -> %in", res->ai_flags) ;
printf("ai_family -> %in", res->ai_family) ;
printf("ai_socktype -> %in", res->ai_socktype) ;
printf("ai_protocol -> %in", res->ai_protocol) ;
printf("ai_addrlen -> %in", res->ai_addrlen) ;
struct sockaddr_in* saddr = (struct sockaddr_in*)res->ai_addr;
printf("ai_addr hostname -> %sn", inet_ntoa(saddr->sin_addr));
freeaddrinfo(res);
return 0 ;
}
Результаты :
ai_flags -> 40
ai_family -> 2
ai_socktype -> 1
ai_protocol -> 6
ai_addrlen -> 16
ai_addr hostname -> 127.0.0.1
В файле/etc / hosts у меня есть:
127.0.0.1 localhost
::1 localhost
Getaddrinfo возвращает только 127.0.0.1, а не :: 1 ? Я не понимаю, почему ?
Второй вопрос заключается в том, где я могу найти значение этих интов (40,2,1,6 и т. д.)? Я читал этого человека, но там ничего об этом нет.
Я также хотел узнать, можно ли дать IPv6-адрес (например :: 1), и функция возвращает название: localhost ?
Большое спасибо !!
4 ответов:
@jwodder и @onteria_ хорошо покрыли часть IPv6, поэтому я просто займусь частью numbers :
ai_flags -> 40Вероятно, это будет сумма следующих двух в
/usr/include/netdb.h:# define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */ # define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to chooseЭто семейные протокола, инет, inet6, арх, Unix и др.:
ai_family -> 2 bits/socket.h:78:#define PF_INET 2 /* IP protocol family. */ bits/socket.h:119:#define AF_INET PF_INETЭто тип сокета , stream, dgram, packet, rdm, seqpacket:
ai_socktype -> 1 bits/socket.h:42: SOCK_STREAM = 1, /* Sequenced, reliable, connection-basedБолее высокого уровня протокол, TCP или UDP, TCP6, UDP6, UDPlite, протокол OSPF, ICMP-пакеты, etc:
ai_protocol -> 6Довольно забавно, в
/etc/protocols:tcp 6 TCP # transmission control protocolРазмер
struct sockaddr. (Отличается в зависимости от адреса семьи! Тьфу.)ai_addrlen -> 16Это потому, что вы получаете обратно
struct sockaddr_in, см.linux/in.h:#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ struct sockaddr_in { sa_family_t sin_family; /* Address family */ __be16 sin_port; /* Port number */ struct in_addr sin_addr; /* Internet address */ /* Pad to size of `struct sockaddr'. */ unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)]; };И последний, из
/etc/hosts:)ai_addr hostname -> 127.0.0.1
resтакже содержит полеstruct addrinfo *ai_next;, которое является указателем на дополнительные записи, найденныеgetaddrinfo, или NULL, если других записей не было. Если вы исследуетеres->ai_next, Вы должны найти запись IPv6.Что касается целых полей в A
struct addrinfo, то они соответствуют предопределенным константам с определенными реализацией значениями, А сами целочисленные значения не представляют общего интереса. Если вы хотите знать, что означает данное поле, сравните его с константами, которые могут быть присвоены этому полю. поле (SOCK_STREAM,SOCK_DGRAM, и т.д. ибоai_socktype;IPPROTO_TCP,IPPROTO_UDP, и т.д. дляai_protocol; и так далее) или, дляai_flags, проверить каждый бит, соответствующий предопределенной константе (например,if (res->ai_flags & AI_NUMERICHOST) {printf("ai_flags has AI_NUMERICHOST\n"); }).
extern struct sockaddr_in6 create_socket6(int port, const char * address) { struct addrinfo hints, *res, *resalloc; struct sockaddr_in6 input_socket6; int errcode; /* 0 out our structs to be on the safe side */ memset (&hints, 0, sizeof (hints)); memset (&input_socket6, 0, sizeof(struct sockaddr_in6)); /* We only care about IPV6 results */ hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_DEFAULT; errcode = getaddrinfo (address, NULL, &hints, &res); if (errcode != 0) { perror ("[ERROR] getaddrinfo "); return input_socket6; } resalloc = res; while (res) { /* Check to make sure we have a valid AF_INET6 address */ if(res->ai_family == AF_INET6) { /* Use memcpy since we're going to free the res variable later */ memcpy (&input_socket6, res->ai_addr, res->ai_addrlen); /* Here we convert the port to network byte order */ input_socket6.sin6_port = htons (port); input_socket6.sin6_family = AF_INET6; break; } res = res->ai_next; } freeaddrinfo(resalloc); return input_socket6; }Вот некоторый код, который объясняет это. В принципе, если вы не дадите getaddrinfo несколько подсказок, чтобы он работал только с IPV6, он также даст результаты IPV4. Вот почему вы должны пройти через результаты, как показано на рисунке.
На большинство частей были даны другие ответы, но чтобы ответить на эту заключительную часть:
Я также хотел узнать, можно ли дать IPv6-адрес (например :: 1), и функция возвращает имя : localhost ?
Функция, которую вы хотите, есть
getnameinfo(); при заданном адресе сокета она возвращает строковое имя.
Comments