项目需求,给定一个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 递归结束计算