首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么要在getaddrinfo()返回的列表中获得"localhost“的重复addrinfo对象?

为什么要在getaddrinfo()返回的列表中获得"localhost“的重复addrinfo对象?
EN

Stack Overflow用户
提问于 2016-09-14 04:53:12
回答 2查看 600关注 0票数 1

这是我的密码。

代码语言:javascript
运行
复制
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

int main()
{
    struct addrinfo hints, *res, *p;
    int error;

    memset(&hints, 0, sizeof hints);

    /* If we comment or remove the following line, the duplicate entries
     * disappear */
    hints.ai_family = AF_INET;

    error = getaddrinfo("localhost", "http", &hints, &res);
    if (error != 0) {
        printf("Error %d: %s\n", error, gai_strerror(error));
        return 1;
    }

    for (p = res; p != NULL; p = p->ai_next)
    {
        if (p->ai_family == AF_INET) {
            struct sockaddr_in *addr = (struct sockaddr_in *) p->ai_addr;
            char ip[INET_ADDRSTRLEN];

            printf("ai_flags: %d; ai_family: %d; ai_socktype: %d; "
                   "ai_protocol: %2d; sin_family: %d; sin_port: %d; "
                   "sin_addr: %s; ai_canonname: %s\n",
                   p->ai_flags, p->ai_family, p->ai_socktype,
                   p->ai_protocol, addr->sin_family, ntohs(addr->sin_port),
                   inet_ntop(AF_INET, &addr->sin_addr, ip, INET_ADDRSTRLEN),
                   p->ai_canonname);
        } else if (p->ai_family == AF_INET6) {
            struct sockaddr_in6 *addr = (struct sockaddr_in6 *) p->ai_addr;
            char ip[INET6_ADDRSTRLEN];

            printf("ai_flags: %d; ai_family: %d; ai_socktype: %d; "
                   "ai_protocol: %2d; sin6_family: %d; sin6_port: %d; "
                   "sin6_addr: %s; ai_canonname: %s\n",
                   p->ai_flags, p->ai_family, p->ai_socktype,
                   p->ai_protocol, addr->sin6_family, ntohs(addr->sin6_port),
                   inet_ntop(AF_INET6, &addr->sin6_addr, ip, INET6_ADDRSTRLEN),
                   p->ai_canonname);
        }
    }

    return 0;
}

这是输出。

代码语言:javascript
运行
复制
$ gcc -std=c99 -D_POSIX_SOURCE -Wall -Wextra -pedantic bar.c && ./a.out
ai_flags: 0; ai_family: 2; ai_socktype: 1; ai_protocol:  6; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)
ai_flags: 0; ai_family: 2; ai_socktype: 2; ai_protocol: 17; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)
ai_flags: 0; ai_family: 2; ai_socktype: 1; ai_protocol:  6; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)
ai_flags: 0; ai_family: 2; ai_socktype: 2; ai_protocol: 17; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)

输出结果表明,第一项和第三项完全相同。同样,第二项和第四项完全相同。为什么我们要在结果中得到这些副本呢?

如果我们从代码中注释或删除下面一行,那么重复的条目就会消失。

代码语言:javascript
运行
复制
    /* If we comment or remove the following line, the duplicate entries
     * disappear */
    /* hints.ai_family = AF_INET; */

这里是本例中的输出。

代码语言:javascript
运行
复制
$ gcc -std=c99 -D_POSIX_SOURCE -Wall -Wextra -pedantic bar.c && ./a.out
ai_flags: 0; ai_family: 10; ai_socktype: 1; ai_protocol:  6; sin6_family: 10; sin6_port: 80; sin6_addr: ::1; ai_canonname: (null)
ai_flags: 0; ai_family: 10; ai_socktype: 2; ai_protocol: 17; sin6_family: 10; sin6_port: 80; sin6_addr: ::1; ai_canonname: (null)
ai_flags: 0; ai_family: 2; ai_socktype: 1; ai_protocol:  6; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)
ai_flags: 0; ai_family: 2; ai_socktype: 2; ai_protocol: 17; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)

这就是我的/etc/hosts的样子。

代码语言:javascript
运行
复制
$ cat /etc/hosts
127.0.0.1       localhost
127.0.1.1       debian1

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

如果hints.ai_family = AF_INET在代码中存在,但是如果/etc/hosts中以::1开头的行被注释掉,那么重复条目实际上就消失了。

代码语言:javascript
运行
复制
$ gcc -std=c99 -D_POSIX_SOURCE -Wall -Wextra -pedantic bar.c && ./a.out
ai_flags: 0; ai_family: 2; ai_socktype: 1; ai_protocol:  6; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)
ai_flags: 0; ai_family: 2; ai_socktype: 2; ai_protocol: 17; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)

但是,我仍然想知道为什么/etc/hosts中的/etc/hosts条目会导致重复条目,即使只使用hints.ai_family = AF_INET来选择IPv4条目。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-09-16 19:34:10

这是一个由来已久的bug/功能的glibc。当您在您的IPv6文件中有一个hosts本地主机条目时,如

代码语言:javascript
运行
复制
::1 localhost

它自动用于AF_INET名称解析。2006年11月,Ulrich Drepper提出了这一行为,并发表了以下评论:

nss/nss_files/files-hosts.c (LINE_PARSER):如果可以映射IPv4查询,支持IPv6 6风格的地址。

有些人认为这是错误,虽然至少有两个bug报告对这个主题进行了长时间的讨论(第一个第二个),但没有人真正解释为什么会做出这种更改,所以我想唯一能够做到这一点的人就是Ulrich本人。但是它可能在某些场景中很有用,因为尽管Ulrich自2012年5月起就不再使用glibc,但这段代码仍然存在于glibc的每个现代版本中。

如果您不喜欢这种行为,可以对hosts文件进行调优,使其不具有localhost名称作为IPv6回送地址,使用其他名称,例如:

代码语言:javascript
运行
复制
::1 localhost6

或者使用一些发行版,当人们认为它是一个bug时,实际上正在维护glibc包,比如openSUSE (可能还有SLES/SLED),也就是纠正这种行为

票数 3
EN

Stack Overflow用户

发布于 2016-09-14 06:24:16

检查静态表查找文件中的主机名(/etc/host)。

当有两行具有相同的canonical_hostname 'localhost‘时,getaddrinfo将返回重复的addrinfo。

您的/etc/主机可能如下所示:

代码语言:javascript
运行
复制
 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
 ::1 localhost
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39482704

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档