【问题标题】:When does getaddrinfo return more than one sockaddr struct in the list?getaddrinfo 何时在列表中返回多个 sockaddr 结构?
【发布时间】:2019-09-20 10:06:33
【问题描述】:

我正在使用我找到的一些代码,我正在尝试理解其中的 for 循环 逻辑。

似乎没有使用 for 循环,而且它总是会中断。所以我不明白从 getaddrinfo() 返回什么样的信息会导致它再次循环并检查一些东西?

问题:基本上这个 for 循环试图完成什么?在我看来,它只是检查 list 不为 NULL,因为永远不会发生循环。

tcp_ctx* tcp_new_ctx(INT family, CHAR *host, CHAR *port) {
    struct addrinfo *list = NULL;
    struct addrinfo *e = NULL;
    struct addrinfo hints;
    tcp_ctx         *c = NULL;
    WSADATA         wsa;
    INT             on = 1;

    WSAStartup(MAKEWORD(2, 0), &wsa);

    ZeroMemory(&hints, sizeof(hints));

    hints.ai_family = family;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // try to resolve network address for host
    //list contains linked list of addrinfo structs containing information on the host
    if (getaddrinfo(host, port, &hints, &list) != 0) {
        return NULL;
    }
    c = tcp_alloc(sizeof(tcp_ctx));

    // Traverse linked list from getaddr info
    for (e = list; e != NULL; e = e->ai_next) {
        if (family == AF_INET) {
            memcpy(&c->v4, e->ai_addr, e->ai_addrlen);
            c->ai_addr = (SOCKADDR*)&c->v4;
        } else if (family == AF_INET6) {
            memcpy(&c->v6, e->ai_addr, e->ai_addrlen);
            c->ai_addr = (SOCKADDR*)&c->v6;
        } else {
            return NULL;
        }
        c->ai_addrlen = e->ai_addrlen;
        // create socket and event for signalling
        c->s = socket(family, SOCK_STREAM, IPPROTO_TCP);
        if (c->s != SOCKET_ERROR) {
            // ensure we can reuse same port later
            setsockopt(c->s, SOL_SOCKET, SO_REUSEADDR, (CHAR*)&on, sizeof(on));
        }
        break;
    }
    freeaddrinfo(list);
    return c;
}

【问题讨论】:

  • 循环看起来介于多余和损坏之间。 (它只关心第一个地址。如果第一个地址不是 IPv4 或 IPv6,代码就会中断……但这在当今的互联网上是极不可能的。)
  • FWIW,我同意你的观点,for 语句除了验证 list 不等于 NULL 之外什么都不做。如果目标是查找 IPv4 地址,同时跳过 IPv6 地址,则该循环是有意义的。但这不是循环正在做的事情。
  • 列表中有什么?其他 IP 地址到它执行 getaddrinfo() 的地址?如果我了解 getaddrinfo() 应该返回的列表与多个链接的样子,那么我可能会解决这个问题。但是我不确定。

标签: c windows sockets


【解决方案1】:

列表中有什么?

以下引用来自man page of getaddrinfo of glibc,但 AFAIK 它同样适用于 Windows 版本:

链表可能有多个的原因有多种 addrinfo 结构,包括:网络主机是多宿主的,可通过多种协议访问(例如,AF_INET 和 AF_INET6);要么 相同的服务可从多种套接字类型(一个 例如 SOCK_STREAM 地址和另一个 SOCK_DGRAM 地址)。

所以,基本上主机可以有多种联系方式,getaddrinfo 列出了所有(已知)方式。请注意,同一手册页进一步指出:

通常,应用程序应尝试使用顺序中的地址 在其中返回。 getaddrinfo() 中使用的排序函数在 RFC 3484 中定义;

当然,我们也不知道这是否也适用于 Windows 实现,但如果它在 RFC 中指定,那么可能就是这种情况。

这个 for 循环试图完成什么?

就目前而言,您可以删除循环。不过,我认为可能有理由保留(=修复)它:考虑第一个返回条目的family 既不是AF_INET 也不是AF_INET6 的情况。然后,您问题中的代码将失败 (return NULL;),但列表中可能会有稍后的条目可能包含该系列。

【讨论】:

  • 我通常远离手册页,但这些似乎解释了我需要知道的一切。我明白它现在会返回什么。非常感谢您的帮助!
  • 循环不检查第一个(或任何)返回条目的系列,即e->ai_family;它检查函数参数 family,它也被放入hints.ai_family,要求gai返回的所有和任何条目都必须具有该系列,因此如果多个条目都将是相同的.
猜你喜欢
  • 1970-01-01
  • 2015-07-22
  • 1970-01-01
  • 1970-01-01
  • 2011-11-16
  • 1970-01-01
  • 1970-01-01
  • 2019-06-19
  • 2015-11-30
相关资源
最近更新 更多