項目需求,給定一個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 遞歸結束計算