最近遇到一个需求,根据IPV4/IPV6和子网掩码获取对应的子网地址,根据计算逻辑,自己简单实现了一版算法,如有问题,欢迎指出!
/** * 根据IP地址和子网掩码获取子网段 * 转换规则 * 一个主机的IP地址是202.112.14.137 * 子网掩码是255.255.255.224 分别转换为二进制 maskBit 位数,如果是12,即开头12个1,后面补0,补足位数 * 11001010 01110000 00001110 10001001 * 11111111 11111111 11111111 11100000 * 进行与的运算,即乘法运算:11001010 01110000 00001110 100 00000 * 然后再转换为对应的ip地址进制数即 202.112.14.128 * @author wjj * @param ipType ip类型 IPV4/IPV6 ip 要计算的ip maskBit 子网掩码 例如32 * @date 2022.11.16 * */ public static String getSubnet(String ipType, String ip, Integer maskBit) { // 最终的子网地址 StringBuilder builder = new StringBuilder(); // 1- IPV4的处理 if ("IPV4".equals(ipType)) { // 1.1- 将IPV4根据.分割,转换成数组 String[] ipV4Array = ip.split("\\."); // 1.2- 只有正确的ip地址才进行计算 if (ipV4Array.length == 4) { // 1.3 将分割后的每组数据与子网掩码进行与的运算,得到每组的子网地址 for (String number : ipV4Array) { // 1.4 够八位的话就是八个1 if (maskBit >= 8) { // 1.5 如果掩码全是1,不用做与的计算,地址不变 if (StringUtils.isBlank(builder.toString())) { builder.append(number); } else { builder.append(".").append(number); } maskBit = maskBit - 8; } else { // 1.6 不够八位的话,后面补0补足八位,进行与的运算 if (maskBit > 0) { StringBuilder mask = new StringBuilder(); for (int i = 0; i < maskBit; i++) { mask.append(1); } for (int i = 0; i < 8 - maskBit; i++) { mask.append(0); } String conversion = ConversionOfNumberUtils.conversion(mask.toString(), 2, 10); Long subnetNumber = Long.parseLong(number) & Long.parseLong(conversion); builder.append(".").append(subnetNumber); maskBit = 0; } else { // 1.7 全是0的话,不用作与的计算,地址直接是0 builder.append(".").append(0); } } } } } else if ("IPV6".equals(ipType)) { // 2- IPV6的处理 fe80::ed14:23f6:b8c8:cff6 IPV6 128位 每:代表 16位 ::连续冒号代表的中间是0,无需处理 // 2.1 将IPV6根据:分割,转换为数据进行处理 String[] ipV6Array = ip.split(":"); if (ipV6Array.length > 0) { // 2.2 将数组中的每个元素进行处理 for (String number : ipV6Array) { if (maskBit >= 16) { // 2.3 :: 的处理,计算出来包含了多少位 if (StringUtils.isBlank(number)) { // : 隐掉了几组数据 Integer num = 8 - ipV6Array.length + 1; maskBit = maskBit - 16 * num; builder.append(":"); } else { // 2.4 掩码全是1,不用做与的计算,地址不变 if (StringUtils.isBlank(builder.toString())) { builder.append(number); } else { builder.append(":").append(number); } maskBit = maskBit - 16; } } else { // 2.5 不够十六位的话,补足十六位,进行与的计算 if (maskBit > 0) { StringBuilder mask = new StringBuilder(); for (int i = 0; i < maskBit; i++) { mask.append(1); } for (int i = 0; i < 16 - maskBit; i++) { mask.append(0); } // 将当前组的地址和掩码分别转为为10进制进行与的计算 String conversionMask = ConversionOfNumberUtils.conversion(mask.toString(), 2, 10); String conversionAddress = ConversionOfNumberUtils.conversion(number, 16, 10); Long subnetNumber = Long.parseLong(conversionMask) & Long.parseLong(conversionAddress); // 将计算后的10进行转换为16进制ipV6地址 String conversionIpV6Address = ConversionOfNumberUtils.conversion(subnetNumber.toString(), 10, 16); builder.append(":").append(conversionIpV6Address); maskBit = 0; } else { // 1.7 全是0的话,不用作与的计算,地址直接是0 builder.append(":").append(0); } } } } } return builder.toString(); }
其中进制转换工具类
import java.math.BigInteger; /** * 进制转换工具类 * @author wjj * @date 2022.11.17 * */ public class ConversionOfNumberUtils { /** * 将任意进制的数转换为其他进制 * @param number 要转换的进制数 beforeRadix 转换前的进制数 afterRadix 转换后的进制数 * @author 吴军杰 * @date 2022.11.17 * */ public static String conversion(String number, Integer beforeRadix, Integer afterRadix) { BigInteger integer = new BigInteger(number, beforeRadix); return integer.toString(afterRadix); } }