10

Beej 的简单客户端示例代码遍历从 getaddrinfo() 返回的所有 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;
}
4

5 回答 5

10

是的,您应该遍历所有地址 - 特别是,考虑目标主机启用了 IPv6 地址但您的本地主机没有启用的情况。 getaddrinfo()将返回AF_INET6家庭地址,但socket()orconnect()调用将失败。

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

于 2012-07-20T06:14:16.753 回答
4

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

于 2012-07-20T12:31:23.343 回答
2

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

于 2012-07-20T05:54:06.237 回答
1

是的,您应该遍历所有这些地址——不能保证地址中的第一个(或您选择的任何内容)实际上是有效的。这就是为什么在教程中这样做的原因。

于 2012-07-20T06:16:34.993 回答
0

假设你是新的套接字,在这一点上。是的,这很重要,因为在使用 getaddrinfo 之后,您可以检索地址信息以进行进一步验证。

于 2012-07-20T04:27:51.633 回答