当我为localhost做getaddrinfo时,我没有收到127.0.0.1

时间:2011-04-22 21:35:38

标签: c sockets localhost

我还在学习套接字并且不清楚为什么这不会打印出127.0.0.1。即使我用127.0.0.1替换localhost这个词,我也会收到一些其他的ip,我猜我的是路由器或其他东西。我一直以为这应该返回127.0.0.1。这是我收到的输出:

hostname: 28.30.0.0
hostname: 28.30.0.0
hostname: 28.30.0.0
hostname: 28.30.0.0
hostname: 16.2.0.0
hostname: 16.2.0.0

以下是基本代码:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>

int main()
{
    struct addrinfo* feed_server = NULL;

    getaddrinfo("localhost", NULL, NULL, &feed_server);
    struct addrinfo *res;
    for(res = feed_server; res != NULL; res = res->ai_next)
    {   
        printf("hostname: %s\n", inet_ntoa(*((struct in_addr*)(res->ai_addr))));
    } 

    return 0;
}

3 个答案:

答案 0 :(得分:4)

res->ai_addr的类型为struct sockaddr*,而不是struct in_addr*

你需要做这样的事情:

for(res = feed_server; res != NULL; res = res->ai_next)
{
    /* ideally look at the sa_family here to make sure it is AF_INET before casting */
    struct sockaddr_in* saddr = (struct sockaddr_in*)res->ai_addr;
    printf("hostname: %s\n", inet_ntoa(saddr->sin_addr));
} 

答案 1 :(得分:3)

您应该使用提示来调用getaddrinfo。因为要解析“localhost”或任何/etc/hosts记录hints.af_family必须设置为AF_INET

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>

int main()
{

   struct addrinfo hints;
   memset(&hints, 0, sizeof(struct addrinfo));
   hints.ai_family = AF_INET;
   getaddrinfo("localhost", NULL, &hints, &feed_server);
   struct addrinfo *res;
   for(res = feed_server; res != NULL; res = res->ai_next){   
      struct sockaddr_in* saddr = (struct sockaddr_in*)res->ai_addr;
      printf("hostname: %s\n", inet_ntoa(saddr->sin_addr))
   } 
   return 0;
}

答案 2 :(得分:1)

原始代码存在两个问题:

  1. ai_addr成员指向一个sockaddr,而不是一个结构in_addr,因此像这样抛出它会产生不正确的结果。
  2. 除非您传递的提示不是NULL并且af_family成员设置为AF_INET,否则您不能指望所有返回的地址都是IPv4(struct sockaddr_in类型)。因此,您可以提供指定IPv4的提示或检查生成的addrinfo结构的af_family成员。
  3. 我通常至少在Linux系统上看到的一件事是,localhost的getaddrinfo通常首先返回IPv6 :: 1地址。

    从正在打印的地址中我可以看出,您正在运行的操作系统中包含结构中的sockaddrs长度。例如,OS X上struct sockaddr的定义是:

     struct sockaddr {
          __uint8_t       sa_len;         /* total length */
          sa_family_t     sa_family;      /* [XSI] address family */
          char            sa_data[14];    /* [XSI] addr value (actually larger) */
     };
    

    对于struct sockaddr_in和sockaddr_in6,sa_family之后的下一个成员是总是两个字节的端口。因此,当您将这些结构中的任何一个转换为结构in_addr时,您将获得一个sa_len.sa_family.0.0的地址(假设您没有为getaddrinfo提供端口 - 如果您提供端口,则0.0将替换为ports字节值)。

    因此gettaddr信息会返回两个IPv6地址: 28.30.0.0 - sizeof struct sockaddr_in6 = 28 and af_family = 30

    和两个IPv4地址: 16.2.0.0 - sizeof struct sockaddr_in = 16和af_family = 2

    要正确执行此操作,您可以执行其他答案所说的操作并使用getnameinfo。但是使用inet_ntop(不是inet_ntoa)同样可以。

    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <stdio.h>
    #include <string.h> /* for memset */
    
    int main()
    {
       char addr_buf[64];
       struct addrinfo* feed_server = NULL;
    
       memset(addr_buf, 0, sizeof(addr_buf));
    
       getaddrinfo("localhost", NULL, NULL, &feed_server);
       struct addrinfo *res;
       for(res = feed_server; res != NULL; res = res->ai_next)
       {   
           if ( res->ai_family == AF_INET )
           {
              inet_ntop(AF_INET, &((struct sockaddr_in *)res->ai_addr)->sin_addr, addr_buf, sizeof(addr_buf));
           }
           else
           {
              inet_ntop(AF_INET6, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, addr_buf, sizeof(addr_buf));
           }
    
           printf("hostname: %s\n", addr_buf); 
       } 
    
       return 0;
    }
    

    ```