【问题标题】:IPv4/IPv6 network calculations and validation for Java?Java 的 IPv4/IPv6 网络计算和验证?
【发布时间】:2010-10-08 04:00:02
【问题描述】:

我正在寻找与Net_IPv4Net_IPv6 类似但为Java 编写的包。它需要能够执行以下操作:

  • 验证地址是否有效(例如 127.0.0.1 有效,127.0.0.257 无效)
  • 如果地址包含在子网中,则返回(例如 127.0.0.11 在 127.0.0.0/28 中)
  • 返回给定子网的广播地址(例如,对于 127.0.0.0/28,它是 127.0.0.15)

如果它也可以,那就太棒了:

  • 按顺序返回子网的地址列表
  • 对地址列表进行排序

我可能会编写一个包来完成所有这些工作,但如果有人已经经历了麻烦并且很可能做得更好,我就会使用它。任何人都知道这样一个或多个可以做到这一切的包吗?我们正在扩展到 IPv6,因此如果可能,它需要同时适用于 IPv4 和 IPv6。

感谢您的帮助。

【问题讨论】:

    标签: java networking ip-address


    【解决方案1】:

    也许CIDRUtils 可以帮助你。它使您能够将 CIDR 表示法转换为 IP 范围。

    免责声明:我是 CIDRUtils 的作者。

    【讨论】:

    • 感谢您发布您的答案!请务必仔细阅读FAQ on Self-Promotion。另请注意,每次链接到自己的网站/产品时,都要求发布免责声明。
    • @AndrewBarber 谢谢。我没有意识到这一点。我只是想帮助可能与我遇到同样问题的其他人。无论如何,我会免责声明。
    【解决方案2】:

    它仅适用于 IPv4,但作为 Commons Net 一部分的 SubnetUtils 类具有您正在寻找的功能。基于此,您可以编写 IPv6 版本并将其贡献回项目! :)

    【讨论】:

      【解决方案3】:

      The IPAddress Java library 以多态方式同时支持 IPv4 和 IPv6,包括子网。链接中提供了 javadoc。免责声明:我是项目经理。

      您列出的所有用例都透明地支持 IPv4 和 IPv6。换句话说,它与大多数其他实用程序的不同之处在于下面的代码与 IPv4 或 IPv6 作为输入字符串的工作方式相同。

      验证地址是否有效

          String str = "::1";
          IPAddressString addrString = new IPAddressString(str);
          try {
               IPAddress addr = addrString.toAddress();
               ...
          } catch(IPAddressStringException e) {
              //e.getMessage provides validation issue
          }
      

      如果地址包含在子网中则返回

          String str = "1::1";
          String subnetStr = "1::/64";
          IPAddressString addrString = new IPAddressString(str);
          IPAddressString subnetString = new IPAddressString(subnetStr);
          try {
               IPAddress addr = addrString.toAddress();
               IPAddress subnet = subnetString.toAddress();
               boolean isContained = subnet.contains(addr); //true in this case
               ...
          } catch(IPAddressStringException e) {
              //e.getMessage provides validation issue
          }
      

      返回给定子网的广播地址

          String subnet = "127.0.0.0/28";
          IPAddressString subnetString = new IPAddressString(subnet);
          try {
               IPAddress subnet = subnetString.toAddress();
               IPAddress broadcastAddr = subnet.getHighest();
               ...
          } catch(IPAddressStringException e) {
              //e.getMessage provides validation issue
          }
      

      按顺序返回子网的地址列表

          String subnet = "127.0.0.0/28";
          IPAddressString subnetString = new IPAddressString(subnet);
          try {
               IPAddress subnet = subnetString.toAddress();
               for(IPAddress addr : subnet) {
                   ...
               }
          } catch(IPAddressStringException e) {
              //e.getMessage provides validation issue
          }
      

      对地址列表进行排序

          List<IPAddressString> addrs; 
          Collections.sort(addrs); //IPAddressString implements Comparable
      

      获取一组子网和地址列表(响应 AhmedRana):

          IPAddress subnet = new IPAddressString("192.168.0.0/28").getAddress();
          IPAddress newSubnets = subnet.adjustPrefixLength(1, false);
          System.out.println(newSubnets); //192.168.0.0-8/29
          HashSet<IPAddress> subnetSet = new HashSet<IPAddress>();
          ArrayList<IPAddress> addrList = new ArrayList<IPAddress>();
          for(IPAddress addr : newSubnets.getIterable()) {
              subnetSet.add(addr.toPrefixBlock());
              addrList.add(addr);
          }
          System.out.println(subnetSet);//[192.168.0.0/29, 192.168.0.8/29]
      
          System.out.println(addrList);
                      //[192.168.0.0/29, 192.168.0.1/29, 192.168.0.2/29,
                      //192.168.0.3/29, 192.168.0.4/29, 192.168.0.5/29,
                      //192.168.0.6/29, 192.168.0.7/29, 192.168.0.8/29,
                      //192.168.0.9/29, 192.168.0.10/29, 192.168.0.11/29,
                      //192.168.0.12/29, 192.168.0.13/29, 192.168.0.14/29,
                      //192.168.0.15/29]
      

      可以有很多地址。获取新子网列表更有效的方法是使用前缀块迭代器,它遍历前缀块子网,如图:

          IPAddress subnet = new IPAddressString("192.168.0.0/28").getAddress();
          IPAddress newSubnets = subnet.adjustPrefixLength(1, false);
          System.out.println(newSubnets); // 192.168.0.0-8/29
          Iterator<? extends IPAddress> iterator = newSubnets.prefixBlockIterator();
          while (iterator.hasNext()) {
              System.out.println(iterator.next());
          }
          // 192.168.0.0/29
          // 192.168.0.8/29
      

      【讨论】:

      • 感谢精彩的图书馆。您的图书馆是否支持以下内容。 1. 返回子网中的 IP 地址列表 2. 子网化网络,例如192.168.0.0/28 将其子网划分为两个 /29 网络。它可以返回这两个创建的子网吗?
      • 不客气。是的,它可以做这些事情,我用你的例子的代码更新了答案,在你的例子中产生了两个子网,每个子网有 8 个地址。但是,在回答您的问题时,我现在看到,虽然它可以非常轻松有效地获取子网列表,但将它们作为列表或集合获取很容易,但对于大型子网(遍历许多地址)效率不高,所以我会添加一个前缀块迭代器方法来更有效地执行此操作,它只会遍历子网网络列表。
      • 谢谢 Sean,这个库的任何版本是否与 JRE 1.5 兼容(或者有没有办法使其与 1.5 兼容)?我只对 IPv4 感兴趣。我有一个限制,它必须在具有 Java 5 的系统上运行
      • @AhmedRana 嗨,最新版本的 IPAddress 使用了很多 lambda(在 java 8 中添加),因此移植最新版本的 IPAddress 并不容易。 IPAddress 1.0.0 版可与 Java 7 一起使用,但它缺少我添加到库中的一些功能。 Java 7 中添加的内容不多,因此很容易使该版本与 Java 6 一起使用,但是,Java 6 是 Java 的主要版本,所以我很难说 IPAddress 的 1.0.0 版本是否可以轻松可与 Java 5 一起使用。
      • 我建议您可以使用 1.0.0 版本的代码,看看您是否可以使用 Java 5 使其工作,然后如果您希望使用最新的 IPAddress 中的内容,然后移植只有那些东西。将最新版本的 IPAddress 移植到 Java 5 可能需要做很多工作,主要是由于代码中的 lambda 函数。
      【解决方案4】:

      我是commons-ip-math 的主要贡献者,这是一个开源 Java 库,它提供丰富的 API 来处理最常见的 IPv4、IPv6 和 AS 编号计算。尽管它最近才开源,但它已经在RIPE NCC 内部进行了多年的实战测试。看看如何在下面使用它。

      (所有示例都使用类似的 IPv6 和 AS 编号语法。只需使用 Ipv6、Ipv6Range、Asn 和 AsnRange 类代替。

      • 验证地址是否有效(例如 127.0.0.1 有效,127.0.0.257 无效)
      Ipv4.parse("127.0.0.1");     // IPv4 representation of "127.0.0.1"
      Ipv4.parse("127.0.0.257");   // IllegalArgumentException
      
      • 如果地址包含在子网中则返回(例如 127.0.0.11 在 127.0.0.0/28 中)
      Ipv4Range.parse("127.0.0.0/28").contains(Ipv4.parse("127.0.0.11"));  //true  
      
      • 返回给定子网的广播地址(例如,对于 127.0.0.0/28,它是 127.0.0.15)
      Ipv4Range.parse("127.0.0.0/28").start().upperBoundForPrefix(28)  // 127.0.0.15
      
      • 按顺序返回子网的地址列表
      // Range types are Iterable
      for (Ipv4 ipv4 : Ipv4Range.parse("127.0.0.0/30")) {
        System.out.println(ipv4);
      }
      // Will print:
      127.0.0.0
      127.0.0.1
      127.0.0.2
      127.0.0.3
      
      • 对地址列表进行排序

      虽然库提供了范围类型的比较器(例如比较子网的大小),但没有单个地址的比较器。但是,由于 IPv4、IPv6 和 ASN 类型实现了 Comparable 接口,因此编写自己的代码相当简单:

      List<Ipv4> list = new ArrayList<Ipv4>();
      list.add(Ipv4.of("0.0.0.3"));
      list.add(Ipv4.of("0.0.0.4"));
      list.add(Ipv4.of("0.0.0.2"));
      list.add(Ipv4.of("0.0.0.1"));
      Collections.sort(list, new Comparator<Ipv4>() {
          @Override
          public int compare(Ipv4 left, Ipv4 right) {
              return left.compareTo(right);
          }
      });
      System.out.println(list);
      // Will print:
      [0.0.0.1, 0.0.0.2, 0.0.0.3, 0.0.0.4]
      

      【讨论】:

      【解决方案5】:

      InetAddress 类和相关的子类将是一个很好的起点。

      【讨论】:

        猜你喜欢
        • 2012-03-01
        • 2014-11-01
        • 2013-06-02
        • 2022-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多