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

发布于 2024-11-03 08:39:16 字数 772 浏览 1 评论 0原文

我仍在学习套接字,不清楚为什么这不打印出 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;
}

I am still learning sockets and am unclear why this doesn't print out 127.0.0.1. Even if I replace the word localhost with 127.0.0.1 I receive some other ip's which I guess are my router or something. I always thought this should return 127.0.0.1. Here's the output I receive:

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

Here is the basic code:

#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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

婴鹅 2024-11-10 08:39:16

原始代码有两个问题:

  1. ai_addr 成员指向 sockaddr 而不是 struct in_addr,因此像这样转换它总是会产生不正确的结果。
  2. 除非您传递不为 NULL 的提示并将 af_family 成员设置为 AF_INET,否则您不能期望所有返回的地址都是 IPv4(struct sockaddr_in 类型)。因此,您可以提供指定 IPv4 的提示或检查生成的 addrinfo 结构的 af_family 成员。

我通常至少在 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 将被替换为端口字节值)。

所以 gettaddr info 返回两个 IPv6 地址:
28.30.0.0 - sizeof struct sockaddr_in6 = 28 和 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;
}

````

There are two problems with the original code:

  1. The ai_addr member points to a sockaddr and not a struct in_addr so casting it like that will always produce incorrect results.
  2. Unless you pass a hints that is not NULL and with the af_family member set to AF_INET, you cannot expect all returned addresses to be IPv4 (struct sockaddr_in type). So you can provide the hints to specify IPv4 or check the af_family member of the resulting addrinfo structs.

One thing I typically see at least on Linux systems is that getaddrinfo for localhost usually returns the IPv6 ::1 address first.

From the addresses being printed I can tell you are running on an OS that includes the sockaddrs length in the struct. For example the definition of struct sockaddr on OS X is:

 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) */
 };

For both struct sockaddr_in and sockaddr_in6 the very next member after sa_family is the port which is always two bytes. So when you cast either of these structs to a struct in_addr you will get an address that is sa_len.sa_family.0.0 (assuming you don't provide a port to getaddrinfo - if you provide a port the 0.0 will be replaced with the ports byte values).

So gettaddr info is returning you two IPv6 addresses:
28.30.0.0 - sizeof struct sockaddr_in6 = 28 and af_family = 30

and two IPv4 addresses:
16.2.0.0 - sizeof struct sockaddr_in = 16 and af_family = 2

To do this properly you could do what the other answer said and use getnameinfo. However using inet_ntop (not inet_ntoa) can be equally as good.

#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;
}

```

很快妥协 2024-11-10 08:39:16

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));
} 

res->ai_addr is of type struct sockaddr*, not struct in_addr*.

You need to do something like this:

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));
} 
生活了然无味 2024-11-10 08:39:16

您应该使用 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;
}

You should use hints for call of getaddrinfo. Because to resolve "localhost" or any /etc/hosts record hints.af_family must be set to 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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文