You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取给定IP范围外的所有IP及IP段?求算法与类Java示例

如何计算给定IP范围的补集(即不在范围内的IP地址范围)

核心思路

要搞定这个问题,核心是把IP地址转成可直接比较的整数,通过排序合并给定范围,再找出这些范围之间的"间隙",以及整个IP地址空间首尾未被覆盖的部分。具体步骤拆解下:

  • 把每个IP范围的起始、结束IP转成32位整数(针对IPv4),这样就能用数值大小判断范围的覆盖关系。
  • 给所有给定的IP范围按起始整数从小到大排序。
  • 合并重叠或相邻的范围(比如192.168.0.0-192.168.0.100和192.168.0.90-192.168.0.200要合并成192.168.0.0-192.168.0.200)。
  • 遍历合并后的范围,计算相邻范围之间的间隙,同时检查IP空间起点(0.0.0.0)到第一个范围的起点、最后一个范围的终点到IP空间终点(255.255.255.255)的空隙,这些就是我们要的"不在给定范围内的IP范围"。

Apex(类Java)实现示例

下面是一个完整的Apex工具类,包含IP与整数互转、范围合并、补集计算的方法:

public class IpRangeUtils {
    // 将IPv4地址转换为32位整数
    public static Long ipToLong(String ip) {
        String[] octets = ip.split('\\.');
        if (octets.size() != 4) {
            throw new IllegalArgumentException('Invalid IPv4 address: ' + ip);
        }
        Long result = 0;
        for (Integer i = 0; i < 4; i++) {
            Integer octet = Integer.valueOf(octets[i]);
            if (octet < 0 || octet > 255) {
                throw new IllegalArgumentException('Invalid octet value: ' + octet);
            }
            result |= octet << (24 - (i * 8));
        }
        return result;
    }

    // 将32位整数转换回IPv4地址
    public static String longToIp(Long ipLong) {
        if (ipLong < 0 || ipLong > 4294967295L) {
            throw new IllegalArgumentException('Invalid IP integer value: ' + ipLong);
        }
        String[] octets = new String[4];
        for (Integer i = 0; i < 4; i++) {
            octets[i] = String.valueOf((ipLong >> (24 - (i * 8))) & 0xFF);
        }
        return String.join(octets, '.');
    }

    // 合并重叠或相邻的IP范围
    public static List<Range> mergeRanges(List<Range> ranges) {
        if (ranges == null || ranges.isEmpty()) {
            return new List<Range>();
        }
        // 按起始IP的整数排序
        ranges.sort((a, b) -> a.startIpLong.compareTo(b.startIpLong));
        
        List<Range> merged = new List<Range>();
        Range current = ranges[0];
        for (Integer i = 1; i < ranges.size(); i++) {
            Range next = ranges[i];
            // 如果当前范围的结束 >= 下一个范围的起始-1(相邻也算),则合并
            if (current.endIpLong >= next.startIpLong - 1) {
                current.endIpLong = Math.max(current.endIpLong, next.endIpLong);
            } else {
                merged.add(current);
                current = next;
            }
        }
        merged.add(current);
        return merged;
    }

    // 计算给定IP范围的补集(即不在范围内的IP范围)
    public static List<Range> calculateComplement(List<Range> inputRanges) {
        List<Range> mergedRanges = mergeRanges(inputRanges);
        List<Range> complement = new List<Range>();
        Long minIp = 0L; // 0.0.0.0
        Long maxIp = 4294967295L; // 255.255.255.255

        // 处理第一个范围之前的间隙
        if (mergedRanges.isEmpty()) {
            complement.add(new Range(minIp, maxIp));
            return complement;
        }
        Range first = mergedRanges[0];
        if (first.startIpLong > minIp) {
            complement.add(new Range(minIp, first.startIpLong - 1));
        }

        // 处理中间的间隙
        for (Integer i = 1; i < mergedRanges.size(); i++) {
            Range prev = mergedRanges[i-1];
            Range curr = mergedRanges[i];
            if (curr.startIpLong > prev.endIpLong + 1) {
                complement.add(new Range(prev.endIpLong + 1, curr.startIpLong - 1));
            }
        }

        // 处理最后一个范围之后的间隙
        Range last = mergedRanges[mergedRanges.size()-1];
        if (last.endIpLong < maxIp) {
            complement.add(new Range(last.endIpLong + 1, maxIp));
        }

        return complement;
    }

    // 辅助类:表示一个IP范围(存储起始和结束的整数形式)
    public class Range {
        public Long startIpLong;
        public Long endIpLong;

        public Range(Long start, Long end) {
            this.startIpLong = start;
            this.endIpLong = end;
        }

        public Range(String startIp, String endIp) {
            this.startIpLong = ipToLong(startIp);
            this.endIpLong = ipToLong(endIp);
        }

        // 输出友好的范围字符串
        public String getRangeString() {
            return longToIp(startIpLong) + ' - ' + longToIp(endIpLong);
        }
    }
}

使用示例

你可以这样调用这个工具类:

// 定义给定的IP范围
List<IpRangeUtils.Range> inputRanges = new List<IpRangeUtils.Range>{
    new IpRangeUtils.Range('192.168.0.0', '192.168.0.100'),
    new IpRangeUtils.Range('10.0.0.0', '10.0.0.255'),
    new IpRangeUtils.Range('192.168.0.90', '192.168.0.200') // 这个会和第一个范围合并
};

// 计算补集
List<IpRangeUtils.Range> complementRanges = IpRangeUtils.calculateComplement(inputRanges);

// 输出结果
for (IpRangeUtils.Range range : complementRanges) {
    System.debug('不在给定范围内的IP范围:' + range.getRangeString());
}

注意事项

  • 这个实现仅针对IPv4地址,如果需要支持IPv6,得修改IP与整数的转换逻辑(IPv6是128位,需要用更大的数值类型或者字符串处理)。
  • 输入的IP范围需要是合法的IPv4地址,否则ipToLong方法会抛出异常,你可以根据需求添加更完善的校验逻辑。

内容的提问来源于stack exchange,提问作者GoldenAxe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:04:36