【问题标题】:extract hex IP from struct addrinfo从 struct addrinfo 中提取十六进制 IP
【发布时间】:2014-05-18 12:14:54
【问题描述】:

我已经用数据填充了我的结构struct addrinfo **res

err = getaddrinfo(argv[1], NULL, &hints, &res);

如果我想打印 IP 地址,我可以使用

addr.s_addr = ((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr;
printf("ip address : %s\n", inet_ntoa(addr));

这将打印例如10.111.1.11。但我需要十六进制格式的 IP,即0A6F010B。 我想出了以下内容,它确实会以十六进制格式打印 IP:

for (i=0; i<32; i=i+8)
    printf("%02X",(addr.s_addr>>i) % 256) ;

但在我看来,我的方法是不必要的复杂。我需要两个步骤(两次转换)。如果可能的话,我想简化我的代码,并直接从 res-&gt;ai_addr-&gt;sa_data 打印十六进制 IP(不必先将数据存储在 addr.s_addr 中)。

我知道res-&gt;ai_addr-&gt;sa_data 中有数据。我可以打印它:

for (i=0; i<14; i++)
    printf("%d", res->ai_addr->sa_data[i]);
printf("\n");

我得到以下输出(对应于10.111.1.11):

001011111100000000

但是格式不像前面的例子那么简单。例如172.25.0.31 我得到这个输出:

00-842503100000000

所以我的问题:

如何将这些乱码转换为十六进制 IP 地址?

【问题讨论】:

  • 如果你想要十六进制,你为什么使用%d,这是十进制?
  • 你也迷路了。你的res 应该是struct addrinfo *

标签: c tcp ip


【解决方案1】:

根据linked questionthis description of sockaddr,您需要进行一些动态类型修改。使用正确的类型,它可能看起来像这样:

struct addrinfo * res;
err = getaddrinfo(argv[1], NULL, &hints, &res);

// check that the operation succeeded
assert(err == 0);

// check that the dynamic type is AF_INET
assert(res->ai_addr->sa_family == AF_INET);

// downcast
struct sockaddr_in * p = (struct sockaddr_in *)(res->ai_addr);

// done
printf("Address: %08X (%s)\n", p->sin_addr.s_addr, inet_ntoa(p->sin_addr));

执行正确的动态类型选择的更完整示例可能如下所示:

char str[128];

switch (res->ai_addr->sa_family)
{
  case AF_INET:
  {
      struct sockaddr_in * p = (struct sockaddr_in *)(res->ai_addr);
      if (inet_ntop(p->sin_family, &p->sin_addr, str, sizeof str) == NULL)
          fprintf(stderr, "Error in inet_ntop: %s\n", strerror(errno));
      else
          printf("Address: %08X (%s)\n", p->sin_addr.s_addr, str);
      break;
  }
  case AF_INET6:
  {
      struct sockaddr_in6 * p = (struct sockaddr_in6 *)(res->ai_addr);
      if (inet_ntop(p->sin6_family, &p->sin6_addr, str, sizeof str) == NULL)
          fprintf(stderr, "Error in inet_ntop: %s\n", strerror(errno));
      else
          printf("Address: %s\n", str);
      break;
  }
  default:
  {
      fprintf(stderr, "Unrecogized address family, skipping.\n");
  }
}

【讨论】:

  • 但这会反向打印十六进制 IP,即 0B016F0A 而不是正确的 0A6F010B
  • @MartinVegter:这不是相反的。相反的是你的期望:-)
  • 与其说是我的期望,不如说是我的tftp 服务器的期望。
  • @MartinVegter:我添加了一个方便的函数调用来帮助您的服务器。
  • 这很好,但我仍然需要“反转”十六进制 IP。
【解决方案2】:

看看inet_ntoahere的一个实现:

#define UC(b)   (((int)b)&0xff)

char* net_ntoa(struct in_addr in) {
    static char b[18];
    register char *p;
    p = (char *)&in;
    snprintf(b, sizeof(b), "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
    return (b);
}

您可以通过交换所需格式(即十六进制)来更改它们的实现以满足您的需求:

snprintf(b, sizeof(b), "%02X%02X%02X%02X", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));

请注意,他们的解决方案不是线程安全的,因为它使用函数静态缓冲区进行输出。要使其线程安全,请将函数更改为获取输出缓冲区,并要求缓冲区至少包含 9 个字符(8 个用于十六进制输出,1 个用于空终止符。

【讨论】:

    猜你喜欢
    • 2014-02-18
    • 2015-08-10
    • 2015-06-29
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 2016-04-06
    • 2022-01-25
    相关资源
    最近更新 更多