是否有必要尝试连接getaddrinfo()返回的所有地址?

时间:2012-07-20 04:18:36

标签: c sockets network-programming getaddrinfo

Beej's Simple Client示例代码迭代从getaddrinfo()返回的所有IP地址,直到它可以连接到第一个IP地址。请参阅下面的代码。

这总是必要的,还是可以假设我们只需要尝试连接到getaddrinfo()返回的第一个地址?

memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;

if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    return 1;
}

// ------------------------------------------------------------
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype,
            p->ai_protocol)) == -1) {
        perror("client: socket");
        continue;
    }

    if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("client: connect");
        continue;
    }

    break;
}

5 个答案:

答案 0 :(得分:9)

是的,您应该遍历所有地址 - 特别是,考虑目标主机启用IPv6地址但本地主机没有启用IPv6地址的情况。 getaddrinfo()会返回AF_INET6个系列地址,但socket()connect()来电将失败。

您的主机也可能支持实现SOCK_STREAM的多个协议(例如,除TCP之外的SCTP),而目标主机不支持 - 因为您尚未设置ai_protocol成员提示结构,将返回代表支持SOCK_STREAM套接字的所有协议的地址。

答案 1 :(得分:4)

除了上面给出的其他答案之外,考虑一般情况,对于较大的网站等,可能会发布多个A记录,以用于冗余目的。如果第一个地址的connect()失败,您也想尝试其他地址。

答案 2 :(得分:2)

让我们以这种方式看看这个...你要连接的服务器主机可能有几个与之关联的地址,但实际的服务器程序只监听其中一个地址。如果您的客户端不知道服务器程序正在侦听的确切地址,则必须先尝试主机所具有的所有地址,直到找到正确的地址并进行连接。

答案 3 :(得分:1)

是的,你应该遍历所有这些 - 不能保证地址中的第一个(或你选择的任何一个)实际上是有效的。这就是为什么它在教程中完成的原因。

答案 4 :(得分:0)

此时假设您是socket的新手。是的,这很重要,因为在使用getaddrinfo之后,您可以检索地址信息以进一步验证。