IP段转为CIDR格式,自我感觉是最优解

项目需求,给定一个IP段,转为CIDR格式表示。

算法思想参照:http://blog.sina.com.cn/s/blog_b1e0018a0102wjdu.html ,加入我自己的理解稍作改动,实现IP段到CIDR的转换。

 

例如:给定 192.168.6.73  -  192.168.6.132

   转换为:

    192.168.6.73/32

    192.168.6.74/31

    192.168.6.76/30

    192.168.6.80/28    

    192.168.6.96/27

    192.168.6.128/30

    192.168.6.132/32
 
废话不多说,直接上代码:
package com.comment.test;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * ip 转掩码位
 *
 */
public class Yanma {

    public static void main(String[] args) throws UnknownHostException {
        List<String> list = new ArrayList<>();
        run("1.1.1.1","1.1.2.32",list);

        list.forEach(li ->{
            System.out.println(li);
        });
    }

    /**
     * 二进制转换ip
     * @param strIp
     * @return
     */
    public static String longToIp(String strIp){
        int ip_1 = Integer.parseInt(strIp.substring(0, 8), 2);
        int ip_2 = Integer.parseInt(strIp.substring(8, 16), 2);
        int ip_3 = Integer.parseInt(strIp.substring(16, 24), 2);
        int ip_4 = Integer.parseInt(strIp.substring(24, 32), 2);
        return ip_1 + "." + ip_2 + "." +ip_3 + "." + ip_4;
    }

    /**
     * ip + 1
     * @param strIp
     * @return
     */
    public static String ipAdd(String strIp){
        String[] split = strIp.split("\\.");
        int ip_1 = Integer.valueOf(split[0]);
        int ip_2 = Integer.valueOf(split[1]);
        int ip_3 = Integer.valueOf(split[2]);
        int ip_4 = Integer.valueOf(split[3]);
        // ip_4  + 1
        if(++ip_4 > 255){
            ip_4 = 0;
            if(++ip_3 > 255){
                ip_3 = 0;
                if(++ip_2 > 255){
                    ip_2 = 0;
                    if(++ip_1 > 255){
                        ip_1 = 0;
                    }
                }
            }
        }

        return ip_1 + "." + ip_2 + "." +ip_3 + "." + ip_4;
    }

    /**
     * ip段范围的 网段
     * @param startIp
     * @param endIp
     * @param networkList
     * @return
     * @throws UnknownHostException
     */
    public static List<String> run(String startIp, String endIp, List<String> networkList) throws UnknownHostException {
        DecimalFormat decimalFormat = new DecimalFormat("00000000000000000000000000000000");
        // 开始ip
        byte[] startByte = InetAddress.getByName(startIp).getAddress();
        String startStr = decimalFormat.format(new BigDecimal(new BigInteger(1, startByte).toString(2)));
        // 结束ip
        byte[] endByte = InetAddress.getByName(endIp).getAddress();
        String endStr = decimalFormat.format(new BigDecimal(new BigInteger(1, endByte).toString(2)));
        // startIp == endIp
        if(startIp.equals(endIp)){
            networkList.add(startIp + "/32");
            return networkList;
        }

        if((startStr).compareTo(endStr) > 0) {
            return networkList;
        }

        // 最短掩码
        int net = startStr.lastIndexOf("1") + 1;
        for(int i = net; i <= 32; i++){
            // startip/net 表示的最大ip地址
            String substring = startStr.substring(0, i);
            String replace = startStr.substring(i).replace("0", "1");
            // 最大ip
            String maxNetwork = longToIp(substring + replace);
            // 如果最大ip小于end
            if((substring + replace).compareTo(endStr) <= 0 || i == 32) {
                networkList.add(startIp + "/" + i);
                // ip + 1
                run(ipAdd(maxNetwork), endIp, networkList);
                break;
            }
        }

        return networkList;
    }

}

运行结果:

示例一:

192.168.6.73  -  192.168.6.132

 

示例二:

1.1.1.32 - 1.1.2.132

 

 举个计算过程的例子:

使用了递归来实现。
首先截止条件是 startip >= endip
startip = endip 的时候向集合添加当前ip/32

分解每一步的操作,以192.168.6.73-192.168.6.132 为例:
	
	第一次计算:
		startip = 192.168.6.73 startStr = 11000000 10101000 00000110 01001001
		最后一个 1 出现的位置是32
		192.168.6.73/32 表示自己 192.168.6.73 ,符合小于结束ip 192.168.6.132 
		所以第一次计算得到CIDR:192.168.6.73/32 表示的范围是:192.168.6.73 - 192.168.6.73
	
	第二次计算:
		startip = 192.168.6.74 startStr = 11000000 10101000 00000110 01001010
		最后一个 1 出现的位置是31
		192.168.6.74/31 表示最大为 192.168.6.75 ,符合小于结束ip 192.168.6.132 
		所以第二次计算得到CIDR:192.168.6.73/31 表示的范围是:192.168.6.74 - 192.168.6.75
	
	第三次计算:
		startip = 192.168.6.76 startStr = 11000000 10101000 00000110 01001100
		最后一个 1 出现的位置是30
		192.168.6.76/30 表示最大为 192.168.6.79 ,符合小于结束ip 192.168.6.132 
		所以第三次计算得到CIDR:192.168.6.76/30 表示的范围是:192.168.6.76 - 192.168.6.79
		
	第四次计算:
		startip = 192.168.6.80 startStr = 11000000 10101000 00000110 01010000
		最后一个 1 出现的位置是28
		192.168.6.80/28 表示最大为 192.168.6.95 ,符合小于结束ip 192.168.6.132 
		所以第四次计算得到CIDR:192.168.6.80/28 表示的范围是:192.168.6.80 - 192.168.6.95
		
	第五次计算:
		startip = 192.168.6.96 startStr = 11000000 10101000 00000110 01100000
		最后一个 1 出现的位置是27
		192.168.6.96/27 表示最大为 192.168.6.127 ,符合小于结束ip 192.168.6.132 
		所以第五次计算得到CIDR:192.168.6.96/27 表示的范围是:192.168.6.96 - 192.168.6.127
	
	第六次计算:
		startip = 192.168.6.128 startStr = 11000000 10101000 00000110 10000000
		最后一个 1 出现的位置是25
		192.168.6.128/25 表示最大为 192.168.6.255 ,不符合小于结束ip 192.168.6.132 
		所以 掩码位 25 不合适 ,往后推一位 26
		192.168.6.128/26 表示最大为 192.168.6.191 ,不符合小于结束ip 192.168.6.132 
		所以 掩码位 26 不合适 ,往后推一位 27
		192.168.6.128/27 表示最大为 192.168.6.159 ,不符合小于结束ip 192.168.6.132 
		所以 掩码位 27 不合适 ,往后推一位 28
		192.168.6.128/28 表示最大为 192.168.6.143 ,不符合小于结束ip 192.168.6.132
		所以 掩码位 28 不合适 ,往后推一位 29
		192.168.6.128/29 表示最大为 192.168.6.135 ,不符合小于结束ip 192.168.6.132
		所以 掩码位 29 不合适 ,往后推一位 30
		192.168.6.128/30 表示最大为 192.168.6.131 ,符合小于结束ip 192.168.6.132
		所以第六次计算得到CIDR:192.168.6.128/30 表示的范围是:192.168.6.128 - 192.168.6.131
		
	第七次计算:
		startip = 192.168.6.132 startStr = 11000000 10101000 00000110 10000100
		startip = endip 符合截止条件
		计算结果为:192.168.6.132/32
		
	递归结束计算

  

 

posted @ 2020-10-12 19:32  董秀才  阅读(3429)  评论(0编辑  收藏  举报