java 计算网段范围 分析网段包含关系

目录

一、网段范围

二、思路说明

三、代码

1、将一个ip转为数字

2、转换子网掩码(255.255.255.0  转为  24)

3、根据 ip 与 掩码 计算最大值和最小值

4、测试

5、完整代码

四、难点讲解

1、转换子网掩码, 例:255.255.255.0  转为  24

2、根据 ip 与 掩码 的二进制 计算最大值和最小值


一、网段范围

大家在开发过程中可能会遇到对比网段的逻辑,让我们先来了解了解常见的网段范围写法

第一种   192.168.0.0-192.168.0.255

第二种   192.168.0.222  255.255.255.0

第三种   192.168.0.222/24

二、思路说明

如果一个ip可以用一个数字表示,那么就可以把一个网段范围用一个数字范围表示,这样就可以直接用大于小于等于来对比,听起来是不是很简单!

我们知道在判断时,将网段ip转为二进制 , 子网掩码也转为二进制, 然后将对比的ip也转为二进制,若(网段ip二进制每一位 并 子网掩码二进制 ) 等于 (对比的ip二进制每一位 并 子网掩码二进制),则该该ip 在网段范围中,反之则不在网段范围中。

所以,将一个ip用数字表示,可以先转为二进制,然后根据掩码算出最大最小的二进制值,然后就可以转回十进制进行对比了。

将网段ip 转为二进制(如下图,192.168.0.222 用数字 3232235742 代表)

前面说的第一种网段范围情况:直接用横杠分割,根据第一个得出最小值,根据第二个得出最大值

前面说的第二种网段范围情况:将子网掩码转成一个数字,第三种一样处理

前面说的第三种网段范围情况:最小值根据掩码将二进制可变位变为零,最大值根据掩码将二进制可变位变为零

三、代码

1、将一个ip转为数字

    public static BigInteger getBigIntegerByip(String ip) {

        BigInteger result = BigInteger.ZERO;

        String[] addrSegments = ip.split("\\.");
        for(int i = 0; i < 4; i++){
            //ip以 "点" 分成4个数, 第一个数左移24位, 第二个数左移16位, 第三个数左移8位,第四个不移,将它们相加
            BigInteger bigInteger = BigInteger.valueOf(Long.parseLong(addrSegments[i]))
                    .shiftLeft(8 * (3 - i));
            result = result.add(bigInteger);
        }

        return result;

    }

2、转换子网掩码(255.255.255.0  转为  24)

    private static IpRangeData getIpRangeDataByMask(String ipSubnetMask) {

        String[] split = ipSubnetMask.split(" ");

        String binaryMask = subnetMaskToBinary(split[1]);

        int zero = binaryMask.indexOf("0");
        int one = binaryMask.lastIndexOf("1");

        if(zero != -1 && one != -1 && zero < one) {
            //反掩码情况
            return null;
        }

        return getIpRangeDataByMask(split[0], zero == -1 ? 32 : zero);

    }

3、根据 ip 与 掩码 计算最大值和最小值

    private static IpRangeData getIpRangeDataByMask(String ip, int mask) {

        int varBin = 32 - mask;

        BigInteger bigIntegerByip = getBigIntegerByip(ip);

        BigInteger min = bigIntegerByip.shiftRight(varBin).shiftLeft(varBin);

        BigInteger varFulll = BigInteger.ONE.shiftLeft(varBin).subtract(BigInteger.ONE);

        BigInteger max = min.add(varFulll);

        IpRangeData result = new IpRangeData();
        result.setStart(min);
        result.setEnd(max);

        return result;

    }

4、测试

 

5、完整代码


import java.math.BigInteger;

/**
 * ip工具类
 *
 * @author zenglingyao
 * @date 2023/07/03
 */
public class IpUtil {

    public static BigInteger getBigIntegerByip(String ip) {

        BigInteger result = BigInteger.ZERO;

        String[] addrSegments = ip.split("\\.");
        for(int i = 0; i < 4; i++){
            //ip以 "点" 分成4个数, 第一个数左移24位, 第二个数左移16位, 第三个数左移8位,第四个不移,将它们相加
            BigInteger bigInteger = BigInteger.valueOf(Long.parseLong(addrSegments[i]))
                    .shiftLeft(8 * (3 - i));
            result = result.add(bigInteger);
        }

        return result;

    }

    /**
     * 解析网段
     *
     * @param segment 段
     * @return {@link IpRangeData}
     */
    public static IpRangeData parseSegment(String segment) {

        String trim = segment.trim();
        if (trim.contains("-")) {

            return getIpRangeDataByRange(trim);

        }else if (trim.contains("/")) {

            String[] split = trim.split("/");
            return getIpRangeDataByMask(split[0], Integer.parseInt(split[1]));

        }else {

            return getIpRangeDataByMask(segment);

        }

    }

    private static IpRangeData getIpRangeDataByRange(String ipRange) {

        String[] split = ipRange.split("-");
        String startIp = split[0];
        String endIp = split[1];

        IpRangeData result = new IpRangeData();
        result.setStart(getBigIntegerByip(startIp));
        result.setEnd(getBigIntegerByip(endIp));

        return result;

    }


    private static IpRangeData getIpRangeDataByMask(String ipSubnetMask) {

        String[] split = ipSubnetMask.split(" ");

        String binaryMask = subnetMaskToBinary(split[1]);

        int zero = binaryMask.indexOf("0");
        int one = binaryMask.lastIndexOf("1");

        if(zero != -1 && one != -1 && zero < one) {
            //反掩码情况
            return null;
        }

        return getIpRangeDataByMask(split[0], zero == -1 ? 32 : zero);

    }


    private static String subnetMaskToBinary(String subnetMask) {

        String[] split = subnetMask.split("\\.");

        StringBuilder result = new StringBuilder();

        for (String subnetMaskArr : split) {

            int decimal = Integer.parseInt(subnetMaskArr);

            StringBuilder target = new StringBuilder();
            for (int i = 0; i < 8; i++) {
                target.insert(0, decimal % 2);
                decimal /= 2;
            }

            result.append(target);

        }

        return result.toString();
    }

    private static IpRangeData getIpRangeDataByMask(String ip, int mask) {

        int varBin = 32 - mask;

        BigInteger bigIntegerByip = getBigIntegerByip(ip);

        BigInteger min = bigIntegerByip.shiftRight(varBin).shiftLeft(varBin);

        BigInteger varFulll = BigInteger.ONE.shiftLeft(varBin).subtract(BigInteger.ONE);

        BigInteger max = min.add(varFulll);

        IpRangeData result = new IpRangeData();
        result.setStart(min);
        result.setEnd(max);

        return result;

    }



    public static void main(String[] args) {

        //32位掩码情况
        String ipMask1 = "192.168.0.1/32";
        String ipSubnetMask1 = "192.168.0.1 255.255.255.255";
        String ipRange1 = "192.168.0.1-192.168.0.1";
        //0位掩码情况
        String ipMask2 = "192.168.0.1/0";
        String ipSubnetMask2 = "192.168.0.1 0.0.0.0";
        String ipRange2 = "0.0.0.0-255.255.255.255";
        //正常掩码情况1
        String ipMask3 = "192.168.0.1/24";
        String ipSubnetMask3 = "192.168.0.1 255.255.255.0";
        String ipRange3 = "192.168.0.0-192.168.0.255";
        //正常掩码情况2
        String ipMask4 = "192.168.0.1/26";
        String ipSubnetMask4 = "192.168.0.1 255.255.255.192";
        String ipRange4 = "192.168.0.192-192.168.0.63";
        //反掩码情况
        String ipSubnetMask5 = "192.168.0.1 255.255.255.247";


        System.out.println("\r\n--------32位掩码情况--------");
        System.out.println(parseSegment(ipMask1));
        System.out.println(parseSegment(ipSubnetMask1));
        System.out.println(parseSegment(ipRange1));


        System.out.println("\r\n---------0位掩码情况--------");
        System.out.println(parseSegment(ipMask2));
        System.out.println(parseSegment(ipSubnetMask2));
        System.out.println(parseSegment(ipRange2));


        System.out.println("\r\n--------正常掩码情况1--------");
        System.out.println(parseSegment(ipMask3));
        System.out.println(parseSegment(ipSubnetMask3));
        System.out.println(parseSegment(ipRange3));


        System.out.println("\r\n--------正常掩码情况2--------");
        System.out.println(parseSegment(ipMask4));
        System.out.println(parseSegment(ipSubnetMask4));
        System.out.println(parseSegment(ipRange4));


        System.out.println("\r\n---------反掩码情况---------");
        System.out.println(parseSegment(ipSubnetMask5));


    }

}


class IpRangeData {

    BigInteger start;
    BigInteger end;

    public BigInteger getStart() {
        return start;
    }

    public void setStart(BigInteger start) {
        this.start = start;
    }

    public BigInteger getEnd() {
        return end;
    }

    public void setEnd(BigInteger end) {
        this.end = end;
    }

    @Override
    public String toString() {
        return "开始值为:" + start + ", 结束值为" + end;
    }
}

四、难点讲解

1、转换子网掩码, 例:255.255.255.0  转为  24

①将 255.255.255.0 先转为  1111 1111   1111 1111    1111 1111      0000 0000

②判断第一个0与最后一个1的位置关系是否正确(判断是否反掩码),第一个0下标为结果

2、根据 ip 与 掩码 的二进制 计算最大值和最小值

①最小值

可变位全为0时最小,比如最后5位是可变位,先右移5位(最右面的5位无论是0还是1都没了),再左移5位(最右面加回来五个0)

②最大值

可变位全为1时最大,比如最后5位是可变位,前面得到的最小值加5个1就行了,如何得到5个1对应的数,把1左移5位 得到 100000 ,这个数减1 得  11111

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值