目录
一、网段范围
二、思路说明
三、代码
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




















