【问题标题】:in_addr_t, jump from one IP to the nextin_addr_t,从一个IP跳转到下一个
【发布时间】:2014-03-10 15:35:38
【问题描述】:

我的程序旨在浏览一系列 IP,由起始 IP 和结束 IP 分隔。以下是本地无线网络上的示例:

MyIP & Netmask = 192.168.1.0
MyIP | ~Netmask = 192.168.1.255

我的程序必须能够遍历所有可用的 IP,从 192.168.1.1 到 192.168.1.254,但我找不到一个恒定或“正确”的方法来获取一个 IP 和另一个之间的距离。这是我用于测试的示例程序:

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

int main(int argc, char** argv)
{
      struct sockaddr_in addr1, addr2, addr3, addr4, addr5;

      addr1.sin_addr.s_addr = inet_addr("192.168.1.1");
      addr2.sin_addr.s_addr = inet_addr("192.168.1.2");
      addr3.sin_addr.s_addr = inet_addr("192.168.1.3");
      addr4.sin_addr.s_addr = inet_addr("192.168.1.255");
      addr5.sin_addr.s_addr = inet_addr("192.168.2.1");

      fprintf(stdout, "addr2 - addr1 = %u\n", addr2.sin_addr.s_addr - addr1.sin_addr.s_addr);
      fprintf(stdout, "addr3 - addr2 = %u\n", addr3.sin_addr.s_addr - addr2.sin_addr.s_addr);
      fprintf(stdout, "addr4 - addr3 = %u\n", addr4.sin_addr.s_addr - addr3.sin_addr.s_addr);
      fprintf(stdout, "addr5 - addr4 = %u\n", addr5.sin_addr.s_addr - addr4.sin_addr.s_addr);

      return EXIT_SUCCESS;
}

我得到以下输出:

addr2 - addr1 = 16777216
addr3 - addr2 = 16777216
addr4 - addr3 = 4227858432
addr5 - addr4 = 33619968

现在,我明白为什么 192.168.1.1 和 192.168.1.2 之间的距离是 16777216 (2^24)。现在,有什么方法可以“正确”获得上述值,如果可能的话,使用预定义的常量(以点格式操作 IP 字符串并不是真正的解决方案)?

  • 要从 192.168.1.1 跳转到 192.168.1.2,我需要向 in_addr_t 值添加什么?
  • 我需要在in_addr_t 值中添加什么才能在更大的子网上从 175.1.1.255 跳转到 175.1.2.0?那么 A 类 IP 呢?
  • 如果我的子网更具体,是否可以使用网络信息确定“间隙”值?
  • 我是否缺少一种更简单/更简洁的方法来解决我的迭代问题?

【问题讨论】:

  • 可能是字节序。以十六进制打印地址的值,看看是否有模式。

标签: c networking ip-address


【解决方案1】:

这是一个字节序问题

在您的系统中,inet_addr("192.168.1.1") 以这种方式返回以 4 个八位字节表示的 IP 地址:

    0x01 | 0x01 | 0xA8 | 0xC0
//    1  .   1  .  168 . 192

inet_addr("192.168.1.2") 返回

    0x02 | 0x01 | 0xA8 | 0xC0
//    2  .   1  .  168 . 192

inet_addr("192.168.1.2") - inet_addr("192.168.1.2") 的区别是:

0x0201A8C0 - 0x0101A8C0 = 0x1000000 // in decimal is 16777216

为每个inet_addr() 使用htonl() 函数以避免字节序问题

所以inet_addr("192.168.1.2") 中的htonl() 将返回

    0xC0 | 0xA8 | 0x01 | 0x02
//   192 .  168 .   1  . 2

htonl() 中的inet_addr("192.168.1.1") 返回

    0xC0 | 0xA8 | 0x01 | 0x01
//   192 .  168 .   1  . 1

然后差将等于1

      addr1.sin_addr.s_addr = htonl(inet_addr("192.168.1.1"));
      addr2.sin_addr.s_addr = htonl(inet_addr("192.168.1.2"));
      addr3.sin_addr.s_addr = htonl(inet_addr("192.168.1.3"));
      addr4.sin_addr.s_addr = htonl(inet_addr("192.168.1.255"));
      addr5.sin_addr.s_addr = htonl(inet_addr("192.168.2.1"));

【讨论】:

  • 如果认为他应该使用ntohl从网络排序转换为主机排序...htonl从主机排序转换为网络排序。
  • 网络字节排序...我怎么会错过呢?我将遍历网络排序值并使用ntohl 在我的主机的相对上下文中设置新的in_addr_t。非常感谢您的详细解答!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-01
  • 2021-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-09
  • 2021-11-16
相关资源
最近更新 更多