当我为本地主机执行getaddrinfo时,我没有收到127.0.0.1

2 c sockets localhost

我仍在学习套接字,并且不清楚为什么它不能打印出127.0.0.1。即使我将localhost替换为127.0.0.1,我也会收到其他一些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
Run Code Online (Sandbox Code Playgroud)

这是基本代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*ter 5

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));
} 
Run Code Online (Sandbox Code Playgroud)

  • 正确的诊断,但错误的解决方案。“ inet_ntoa”已被弃用,并且需要使用丑陋的特定于地址族的代码(即特定于IPv4的代码)。而是将getnameinfo与NI_NUMERICHOST一起使用,以将地址转换回数字形式的字符串。 (4认同)
  • 您需要考虑 getaddrinfo 可能返回非 IPv4 地址的事实。在某些情况下,无条件转换为 sockaddr_in 会给出不正确的结果。 (2认同)

Mat*_*att 5

原代码有两个问题:

  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) */
 };
Run Code Online (Sandbox Code Playgroud)

对于 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;
}
Run Code Online (Sandbox Code Playgroud)

````