为什么 inet_ntoa 总是返回 0.0.0.0 作为 ip 地址?

Why is inet_ntoa always returning me 0.0.0.0 as the ip address?

我不明白,因为下面的代码总是返回 0.0.0.0 作为 google.com 的 IP 地址。我需要使用 inet_ntoa 而没有其他功能。谁能帮我算出 pb?

#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //for exit(0);
#include<sys/socket.h>
#include<errno.h> //For errno - the error number
#include<netdb.h> //hostent
#include<arpa/inet.h>

int hostname_to_ip(char *  , char *);

int main(int argc , char *argv[])
{
    if(argc <2)
    {
        printf("Please provide a hostname to resolve");
        exit(1);
    }

    char *hostname = argv[1];
    char ip[100];

    hostname_to_ip(hostname , ip);
    printf("%s resolved to %s" , hostname , ip);

    printf("\n");

}
/*
    Get ip from domain name
 */

int hostname_to_ip(char *hostname , char *ip)
{
    int sockfd;  
    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_in *h;
    int rv;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
    hints.ai_socktype = SOCK_STREAM;

    if ( (rv = getaddrinfo( hostname , "http" , &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) 
    {
        h = (struct sockaddr_in *) p->ai_addr;
        strcpy(ip , inet_ntoa( h->sin_addr ) );
    }

    freeaddrinfo(servinfo); // all done with this structure
    return 0;
}

它实际上是取自 http://www.binarytides.com/hostname-to-ip-address-c-sockets-linux/ 的代码,但我的代码几乎做同样的事情,尤其是它使用了我正在寻找的相同功能。

我编译: $ gcc hostname_to_ip.c && ./a.out www.google.com

getaddrinfo() 函数 return 是一个地址链表,客户可以从中选择。您可以通过传递给该函数的 "hints" 对象来影响列表中包含哪些地址。在使用 inet_ntoa() 处理获得的地址时,您假设是 IPv4。那么,告诉 getaddrinfo() 您只对 IPv4 地址感兴趣是有道理的:

hints.ai_family = AF_INET;

我可以用您的原始代码重现您的结果,但进行一次修改后我会得到一个外观合理的 IPv4 地址。

虽然您确实遍历了 getaddrinfo() 提供的地址列表,但当您转换为 struct sockaddr_in * 而不检查地址族时,您 假设 每个地址它在家庭 AF_INET 中。那是不安全的。此外,您会用下一个覆盖每个转换后的地址字符串,因此如果 getaddrinfo() 很好地确定了您最可能需要的地址的优先级,那么您就会把它变成破损。

如果您没有指定只需要 IPv4 地址,那么至少您应该在决定是否使用之前检查每个 returned 地址的系列。而且,你只有return一个,所以当你找到一个你可以使用的时候,你还不如跳出循环。