C语言 getaddrinfo 和 IPv6

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5956516/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 08:37:17  来源:igfitidea点击:

getaddrinfo and IPv6

cnetwork-programmingipv6ipv4getaddrinfo

提问by lilawood

I'm trying to understand what the getaddrinfo function returns :

我试图了解 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 -> %i\n", res->ai_flags) ;
  printf("ai_family -> %i\n", res->ai_family) ;
  printf("ai_socktype -> %i\n", res->ai_socktype) ;
  printf("ai_protocol -> %i\n", res->ai_protocol) ;
  printf("ai_addrlen -> %i\n", res->ai_addrlen) ;
  struct sockaddr_in* saddr = (struct sockaddr_in*)res->ai_addr;
  printf("ai_addr hostname ->  %s\n", inet_ntoa(saddr->sin_addr));

  freeaddrinfo(res);

  return 0 ;
}

results :

结果 :

ai_flags -> 40
ai_family -> 2
ai_socktype -> 1
ai_protocol -> 6
ai_addrlen -> 16
ai_addr hostname ->  127.0.0.1

In /etc/hosts, I 've got :

在 /etc/hosts 中,我有:

127.0.0.1 localhost    
::1     localhost

Getaddrinfo returns only 127.0.0.1 and not ::1 ? I don't understand why ?

Getaddrinfo 仅返回 127.0.0.1 而不是 ::1 ?我不明白为什么?

The second question is where can I find the meaning of those ints (40,2,1,6 etc) ? I've read the man but there is nothing about that.

第二个问题是我在哪里可以找到这些整数(40,2,1,6 等)的含义?我读过那个人,但没有什么。

I also wanted to know if it's possible to give a IPv6 adress (for example ::1) and the function returns the name : localhost ?

我还想知道是否可以提供 IPv6 地址(例如 ::1)并且该函数返回名称 : localhost ?

Thanks a lot !!

非常感谢 !!

采纳答案by sarnold

@jwodder and @onteria_ covered the IPv6 portion well, so I'll just tackle the numbersportion:

@jwodder 和 @onteria_ 很好地涵盖了 IPv6 部分,所以我将只处理数字部分:

ai_flags -> 40

Probably this is going to be the sum of the following two in /usr/include/netdb.h:

可能这将是以下两个的总和/usr/include/netdb.h

# define AI_V4MAPPED    0x0008  /* IPv4 mapped addresses are acceptable.  */
# define AI_ADDRCONFIG  0x0020  /* Use configuration of this host to choose

This is the protocol family, inet, inet6, apx, unix, etc.:

这是协议族、inet、inet6、apx、unix 等:

ai_family -> 2

bits/socket.h:78:#define    PF_INET     2   /* IP protocol family.  */
bits/socket.h:119:#define   AF_INET     PF_INET

This is the socket type, stream, dgram, packet, rdm, seqpacket:

这是套接字类型、流、dgram、数据包、rdm、seqpacket:

ai_socktype -> 1

bits/socket.h:42:  SOCK_STREAM = 1,     /* Sequenced, reliable, connection-based

The higher-level protocol, TCP, UDP, TCP6, UDP6, UDPlite, ospf, icmp, etc:

高层协议,TCP、UDP、TCP6、UDP6、UDPlite、ospf、icmp等:

ai_protocol -> 6

Funny enough, in /etc/protocols:

很有趣,在/etc/protocols

tcp 6   TCP     # transmission control protocol

The size of the struct sockaddr. (Differs based on the address family! Ugh.)

的大小struct sockaddr。(因地址族而异!呃。)

ai_addrlen -> 16

This is because you're getting back a struct sockaddr_in, see linux/in.h:

这是因为您要返回 a 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)];
};

And the last one, from /etc/hosts:)

最后一个,来自/etc/hosts:)

ai_addr hostname ->  127.0.0.1

回答by jwodder

resalso contains a field struct addrinfo *ai_next;, which is a pointer to additional entries found by getaddrinfo, or NULL if there were no other entries. If you examine res->ai_next, you should find the IPv6 entry.

res还包含一个字段struct addrinfo *ai_next;,它是指向由 找到的其他条目的指针getaddrinfo,如果没有其他条目,则为 NULL。如果您检查res->ai_next,您应该找到 IPv6 条目。

As for the integer fields in a struct addrinfo, they correspond to predefined constants with implementation-defined values, and the integer values themselves are not of general interest. If you want to know what a given field means, compare it against the constants that can be assigned to that field (SOCK_STREAM, SOCK_DGRAM, etc. for ai_socktype; IPPROTO_TCP, IPPROTO_UDP, etc. for ai_protocol; and so forth) or, for ai_flags, test each bit corresponding to a predefined constant (e.g., if (res->ai_flags & AI_NUMERICHOST) {printf("ai_flags has AI_NUMERICHOST\n"); }).

至于 a 中的整数字段struct addrinfo,它们对应于具有实现定义值的预定义常量,并且整数值本身并不是普遍感兴趣的。如果你想知道某一领域的手段,比较它针对可分配给该字段的常数(SOCK_STREAMSOCK_DGRAM,等了ai_socktype; IPPROTO_TCPIPPROTO_UDP等了ai_protocol;等等),或者用于ai_flags测试对应于每个位预定义常量(例如,if (res->ai_flags & AI_NUMERICHOST) {printf("ai_flags has AI_NUMERICHOST\n"); })。

回答by onteria_

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;
}

Here is some code that explains it. Basically unless you give getaddrinfo some hints to tell it to only work with IPV6, it will also give IPV4 results. That is why you have to loop through the results as shown.

这是一些解释它的代码。基本上,除非你给 getaddrinfo 一些提示,告诉它只适用于 IPV6,否则它也会给出 IPV4 结果。这就是为什么您必须按所示循环遍历结果。

回答by LeoNerd

Other answers have been given to most parts, but to answer this final part:

大多数部分已经给出了其他答案,但要回答最后一部分:

I also wanted to know if it's possible to give a IPv6 adress (for example ::1) and the function returns the name : localhost ?

我还想知道是否可以提供 IPv6 地址(例如 ::1)并且该函数返回名称 : localhost ?

The function you want there is getnameinfo(); given a socket address it returns a string name.

你想要的功能是getnameinfo(); 给定一个套接字地址,它返回一个字符串名称。