从给定的IP地址和子网掩码中获取所有IP地址。

7
在Java中,我需要获取给定IP网络包含的所有IP地址列表。
例如,让网络为:192.168.5.0/24,那么输出将是(192.168.5.0 ... 192.168.5.255)。
我能想到以下方法,但它看起来很混乱,是否有更优雅的方法?在InetAddress类中没有相应的函数。
  1. Get Network Ip from the input Ip and subnet mask.

    mask = (long)(0xffffffff) << (32-subnetMask);
    Long netIp = getLongfromIp(Inputip)& mask;
    

函数“getLongfromIp”包含代码- 如何在Java中将字符串(IP数字)转换为整数

  1. 通过子网掩码获取主机数量

    maxRange = (long)0x1<<(32-subnetMask);

  2. 通过将i添加到netIp:for i in (0 .. maxRange),获取所有希望的地址

  3. 将上一步中的IP转换为八进制字符串。

注:我确定IP地址仅为IPv4。


1
什么问题? - erickson
我已经重新表述了我的问题!我的问题是如何获取特定网络中的所有IP地址,例如(192.168.5.0/24),然后输出将为(192.168.5.0 ... 192.168.5.255)。我已经分享了我正在使用的方法,但它很糟糕。我正在寻找更加优雅的解决方案! - Mangat Rai Modi
你会包括子网和广播地址吗?还是只有常规主机地址?你的解决方案中哪些地方让你感到不够优雅? - erickson
是的,我需要它们两个。我不喜欢将八位字符串转换为长整型,然后再反过来。我有一种感觉,可以在不进行转换的情况下完成相同的操作。 - Mangat Rai Modi
1
InetAddress API使用字节数组。使用字节数组中的计数器进行迭代,而不是整数类型,会非常混乱、容易出错,并且速度慢得多。相比之下,使用ByteBuffer进行转换更快捷、简洁。 - erickson
4个回答

12

回答我的问题,解决方案是使用Apache commons.net库。

import org.apache.commons.net.util.*;

SubnetUtils utils = new SubnetUtils("192.168.1.0/24");
String[] allIps = utils.getInfo().getAllAddresses();
//appIps will contain all the ip address in the subnet

阅读更多:SubnetUtils.SubnetInfo 类


1
可以运行。如果他们实现了一个地址迭代器而不是试图把它们全部(可能有数百万个地址)放入数组中,那将会更好。如果他们实现了Spliterator,操作地址的并行化就会变得容易。 - erickson
是的,它很脏。但考虑到它支持IPV4,它仍然可以管理。 - Mangat Rai Modi
1
但它没有获取初始和最终地址。 - Labeo
你是指网络地址和广播地址吗?除非你打算使用广播消息,否则这些地址并没有什么有用的作用。 - RedShift
1
如果您需要包括第一个和最后一个IP地址,请确保将inclusiveHostCount设置为true。 - sedrakpc

5

IPAddress Java库以多态方式支持IPv4和IPv6子网。免责声明:我是项目经理。

以下是示例代码,可透明地列出IPv4或Ipv6子网的地址。子网可能非常大,特别是在IPv6中,尝试迭代整个子网是不明智的,因此iterateEdges的代码显示了如何仅迭代子网中的起始和结束地址。

show("192.168.10.0/24");
show("2001:db8:abcd:0012::/64");

static void show(String subnet) throws AddressStringException {
    IPAddressString addrString = new IPAddressString(subnet);
    IPAddress addr = addrString.toAddress();
    show(addr);
}

static void show(IPAddress subnet) {
    Integer prefixLength = subnet.getNetworkPrefixLength();
    if(prefixLength == null) {
        prefixLength = subnet.getBitCount();
    }
    IPAddress mask = subnet.getNetwork().getNetworkMask(prefixLength, false);
    BigInteger count = subnet.getCount();
    System.out.println("Subnet of size " + count + " with prefix length " + prefixLength + " and mask " + mask);
    System.out.println("Subnet ranges from " + subnet.getLower() + " to " + subnet.getUpper());
    int edgeCount = 3;
    if(count.compareTo(BigInteger.valueOf(256)) <= 0) {
        iterateAll(subnet, edgeCount);
    } else {
        iterateEdges(subnet, edgeCount);
    }
}

迭代整个子网,使用时请小心:

static void iterateAll(IPAddress subnet, int edgeCount) {
    BigInteger count = subnet.getCount();
    BigInteger bigEdge = BigInteger.valueOf(edgeCount), currentCount = count;
    int i = 0;
    for(IPAddress addr: subnet.getIterable()) {
        currentCount = currentCount.subtract(BigInteger.ONE);
        if(i < edgeCount) {
            System.out.println(++i + ": " + addr);
        } else if(currentCount.compareTo(bigEdge) < 0) {
            System.out.println(count.subtract(currentCount) + ": " + addr);
        } else if(i == edgeCount) {
            System.out.println("...skipping...");
            i++;
        }
    }
}

迭代子网边缘:

static void iterateEdges(IPAddress subnet, int edgeCount) {
    for(int increment = 0; increment < edgeCount; increment++) {
        System.out.println((increment + 1) + ": " + subnet.getLower().increment(increment));
    }
    System.out.println("...skipping...");
    BigInteger count = subnet.getCount();
    for(int decrement = 1 - edgeCount; decrement <= 0; decrement++) {
        System.out.println(count.add(BigInteger.valueOf(decrement)) + ": " + subnet.getUpper().increment(decrement));
    }
}

这里是输出:

Subnet of size 256 with prefix length 24 and mask 255.255.255.0
Subnet ranges from 192.168.5.0/24 to 192.168.5.255/24
1: 192.168.5.0/24
2: 192.168.5.1/24
3: 192.168.5.2/24
...skipping...
254: 192.168.5.253/24
255: 192.168.5.254/24
256: 192.168.5.255/24

Subnet of size 18446744073709551616 with prefix length 64 and mask ffff:ffff:ffff:ffff::
Subnet ranges from 2001:db8:abcd:12::/64 to 2001:db8:abcd:12:ffff:ffff:ffff:ffff/64
1: 2001:db8:abcd:12::/64
2: 2001:db8:abcd:12::1/64
3: 2001:db8:abcd:12::2/64
...skipping...
18446744073709551614: 2001:db8:abcd:12:ffff:ffff:ffff:fffd/64
18446744073709551615: 2001:db8:abcd:12:ffff:ffff:ffff:fffe/64
18446744073709551616: 2001:db8:abcd:12:ffff:ffff:ffff:ffff/64

3
人们懒得阅读你的非常好的答案... 你需要更简短 :) - Dirk Hoffmann
不确定为什么,但是 show("10.8.0.1/24"); 没有提供正确的答案。它告诉我只有1个IP是可能的,而实际上有256种变化。show("10.8.0.0/24"); 可以正常工作。 - Macindows
对于具有非零主机的地址,请将“IPAddress addr = addrString.toAddress();”更改为“IPAddress addr = addrString.toAddress().toPrefixBlock();”,以获取前缀块。 - Sean F
1
请查看此处链接的内容:https://github.com/seancfoley/IPAddress/wiki/Code-Examples#parse-prefixed-as-subnet-or-ip-address - Sean F
这是我需要的!谢谢! - Macindows

2

包括NetworkAddress和BroadcastAddress

import org.apache.commons.net.util.*;

 SubnetUtils utils = new SubnetUtils("192.168.1.0/28");
       utils.setInclusiveHostCount(true);

       String[] allIps = utils.getInfo().getAllAddresses();

1
以下是与Sean(非常好!)的答案相同,使用https://seancfoley.github.io/IPAddress/,仅减少信噪比:
subnetToIps("192.168.10.0/28");

    public void subnetToIps(String ipOrCidr) {
        IPAddressString addrString = new IPAddressString(ipOrCidr, IPAddressString.DEFAULT_VALIDATION_OPTIONS);
        IPAddress subnet = addrString.toAddress();
        System.out.println("Subnet ranges from " + subnet.getLower() + " to " + subnet.getUpper());

        int i = 0;
        for (IPAddress addr : subnet.getIterable()) {
            System.out.println(++i + ": " + addr);
        }
    }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接