getaddrinfo何时返回列表中多个sockaddr结构?

Hal*_*een 6 c sockets windows

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

看起来 for 循环没有被使用并且它总是会中断。所以我不明白从 getaddrinfo() 返回什么样的信息会导致它再次循环并检查某些内容?

问题:基本上这个 for 循环想要完成什么?在我看来,它只是检查列表不为空,因为从来没有发生循环。

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;
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*our 6

列表中会有什么?

以下引用来自glibc的手册页getaddrinfo,但据我所知,它同样适用于 Windows 版本:

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

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

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

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

这个 for 循环想要完成什么?

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