diff --git a/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java b/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java index 6c8c89689..617a3b0ed 100755 --- a/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java @@ -1,11 +1,10 @@ package cn.hutool.core.net; import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.Assert; import cn.hutool.core.regex.PatternPool; -import cn.hutool.core.util.CharUtil; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.CharUtil; import java.util.ArrayList; import java.util.List; @@ -17,7 +16,19 @@ import java.util.regex.Matcher; * *

pr自:https://gitee.com/loolly/hutool/pulls/161

* + *

名词解释: + *

+ * * @author ZhuKun + * @author emptypoint * @since 5.4.1 */ public class Ipv4Util { @@ -43,22 +54,57 @@ public class Ipv4Util { public static final int IP_MASK_MAX = 32; /** - * 格式化IP段 + * 最小掩码位 + */ + public static final int IP_MASK_MIN = 1; + + /** + * A类私有地址的最小值 + */ + public static final long A_INNER_IP_LONG_BEGIN = ipv4ToLong("10.0.0.0"); + + /** + * A类私有地址的最大值 + */ + public static final long A_INNER_IP_LONG_END = ipv4ToLong("10.255.255.255"); + + /** + * B类私有地址的最小值 + */ + public static final long B_INNER_IP_LONG_BEGIN = ipv4ToLong("172.16.0.0"); + + /** + * B类私有地址的最大值 + */ + public static final long B_INNER_IP_LONG_END = ipv4ToLong("172.31.255.255"); + + /** + * C类私有地址的最小值 + */ + public static final long C_INNER_IP_LONG_BEGIN = ipv4ToLong("192.168.0.0"); + + /** + * C类私有地址的最大值 + */ + public static final long C_INNER_IP_LONG_END = ipv4ToLong("192.168.255.255"); + + /** + * 根据 ip地址 和 掩码地址 获得 CIDR格式字符串 * - * @param ip IP地址 - * @param mask 掩码 - * @return 返回xxx.xxx.xxx.xxx/mask的格式 + * @param ip IP地址,点分十进制,如:xxx.xxx.xxx.xxx + * @param mask 掩码地址,点分十进制,如:255.255.255.0 + * @return 返回 {@literal xxx.xxx.xxx.xxx/掩码位} 的格式 */ public static String formatIpBlock(final String ip, final String mask) { return ip + IP_MASK_SPLIT_MARK + getMaskBitByMask(mask); } /** - * 智能转换IP地址集合 + * 智能获取指定区间内的所有IP地址 * - * @param ipRange IP段,支持X.X.X.X-X.X.X.X或X.X.X.X/X - * @param isAll true:全量地址,false:可用地址;仅在ipRange为X.X.X.X/X时才生效 - * @return IP集 + * @param ipRange IP区间,支持 {@literal X.X.X.X-X.X.X.X} 或 {@literal X.X.X.X/X} + * @param isAll true:全量地址,false:可用地址;该参数仅在ipRange为X.X.X.X/X时才生效 + * @return 区间内的所有IP地址,点分十进制格式 */ public static List list(final String ipRange, final boolean isAll) { if (ipRange.contains(IP_SPLIT_MARK)) { @@ -75,16 +121,22 @@ public class Ipv4Util { } /** - * 根据IP地址、子网掩码获取IP地址区间 + * 根据 IP地址 和 掩码位数 获取 子网所有ip地址 * - * @param ip IP地址 + * @param ip IP地址,点分十进制 * @param maskBit 掩码位,例如24、32 * @param isAll true:全量地址,false:可用地址 - * @return 区间地址 + * @return 子网所有ip地址 */ public static List list(final String ip, final int maskBit, final boolean isAll) { + assertMaskBitValid(maskBit); + // 避免后续的计算异常 + if (countByMaskBit(maskBit, isAll) == 0) { + return new ArrayList<>(0); + } + if (maskBit == IP_MASK_MAX) { - final List list = new ArrayList<>(); + final List list = new ArrayList<>(isAll ? 1 : 0); if (isAll) { list.add(ip); } @@ -97,6 +149,7 @@ public class Ipv4Util { return list(startIp, endIp); } + // 可用地址,排除开始和结束的地址 int lastDotIndex = startIp.lastIndexOf(CharUtil.DOT) + 1; startIp = StrUtil.subPre(startIp, lastDotIndex) + (Integer.parseInt(Objects.requireNonNull(StrUtil.subSuf(startIp, lastDotIndex))) + 1); @@ -107,17 +160,26 @@ public class Ipv4Util { } /** - * 得到IP地址区间 + * 获得 指定区间内 所有ip地址 * - * @param ipFrom 开始IP - * @param ipTo 结束IP - * @return 区间地址 + * @param ipFrom 开始IP,包含,点分十进制 + * @param ipTo 结束IP,包含,点分十进制 + * @return 区间内所有ip地址 */ public static List list(final String ipFrom, final String ipTo) { + return list(ipv4ToLong(ipFrom), ipv4ToLong(ipTo)); + } + + /** + * 得到指定区间内的所有IP地址 + * + * @param ipFrom 开始IP, 包含 + * @param ipTo 结束IP, 包含 + * @return 区间内所有ip地址,点分十进制表示 + */ + public static List list(final long ipFrom, final long ipTo) { // 确定ip数量 final int count = countByIpRange(ipFrom, ipTo); - final int[] from = Convert.convert(int[].class, StrUtil.splitToArray(ipFrom, CharUtil.DOT)); - final int[] to = Convert.convert(int[].class, StrUtil.splitToArray(ipTo, CharUtil.DOT)); final List ips = new ArrayList<>(count); // 是否是循环的第一个值 @@ -125,24 +187,30 @@ public class Ipv4Util { // 是否是循环的最后一个值 boolean aIsEnd, bIsEnd, cIsEnd; // 循环的结束值 - final int aEnd = to[0]; + final int aEnd = getPartOfIpLong(ipTo, 1); int bEnd; int cEnd; int dEnd; - for (int a = from[0]; a <= aEnd; a++) { + final StringBuilder sb = StrUtil.builder(15); + for (int a = getPartOfIpLong(ipFrom, 1); a <= aEnd; a++) { aIsEnd = (a == aEnd); // 本次循环的结束结束值 - bEnd = aIsEnd ? to[1] : 255; - for (int b = (aIsStart ? from[1] : 0); b <= bEnd; b++) { + bEnd = aIsEnd ? getPartOfIpLong(ipTo, 2) : 255; + for (int b = (aIsStart ? getPartOfIpLong(ipFrom, 2) : 0); b <= bEnd; b++) { // 在上一个循环是最后值的基础上进行判断 bIsEnd = aIsEnd && (b == bEnd); - cEnd = bIsEnd ? to[2] : 255; - for (int c = (bIsStart ? from[2] : 0); c <= cEnd; c++) { + cEnd = bIsEnd ? getPartOfIpLong(ipTo, 3) : 255; + for (int c = (bIsStart ? getPartOfIpLong(ipFrom, 3) : 0); c <= cEnd; c++) { // 在之前循环是最后值的基础上进行判断 cIsEnd = bIsEnd && (c == cEnd); - dEnd = cIsEnd ? to[3] : 255; - for (int d = (cIsStart ? from[3] : 0); d <= dEnd; d++) { - ips.add(a + "." + b + "." + c + "." + d); + dEnd = cIsEnd ? getPartOfIpLong(ipTo, 4) : 255; + for (int d = (cIsStart ? getPartOfIpLong(ipFrom, 4) : 0); d <= dEnd; d++) { + sb.setLength(0); + ips.add(sb.append(a).append(CharUtil.DOT) + .append(b).append(CharUtil.DOT) + .append(c).append(CharUtil.DOT) + .append(d) + .toString()); } cIsStart = false; } @@ -154,46 +222,39 @@ public class Ipv4Util { } /** - * 根据long值获取ip v4地址:xx.xx.xx.xx + * 根据 ip的long值 获取 ip字符串,即:xxx.xxx.xxx.xxx * - * @param longIP IP的long表示形式 - * @return IP V4 地址 + * @param longIp IP的long表示形式 + * @return 点分十进制ip地址 */ - public static String longToIpv4(final long longIP) { - final StringBuilder sb = StrUtil.builder(); - // 直接右移24位 - sb.append(longIP >> 24 & 0xFF); - sb.append(CharUtil.DOT); - // 将高8位置0,然后右移16位 - sb.append(longIP >> 16 & 0xFF); - sb.append(CharUtil.DOT); - sb.append(longIP >> 8 & 0xFF); - sb.append(CharUtil.DOT); - sb.append(longIP & 0xFF); - return sb.toString(); + public static String longToIpv4(final long longIp) { + return StrUtil.builder(15) + .append(getPartOfIpLong(longIp, 1)).append(CharUtil.DOT) + .append(getPartOfIpLong(longIp, 2)).append(CharUtil.DOT) + .append(getPartOfIpLong(longIp, 3)).append(CharUtil.DOT) + .append(getPartOfIpLong(longIp, 4)) + .toString(); } /** - * 根据ip地址(xxx.xxx.xxx.xxx)计算出long型的数据 - * 方法别名:inet_aton + * 将 ip字符串 转换为 long值 + *

方法别名:inet_aton

* - * @param strIP IP V4 地址 - * @return long值 + * @param strIp ip地址,点分十进制,xxx.xxx.xxx.xxx + * @return ip的long值 */ - public static long ipv4ToLong(final String strIP) { - final Matcher matcher = PatternPool.IPV4.matcher(strIP); - if (matcher.matches()) { - return matchAddress(matcher); - } - throw new IllegalArgumentException("Invalid IPv4 address!"); + public static long ipv4ToLong(final String strIp) { + final Matcher matcher = PatternPool.IPV4.matcher(strIp); + Assert.isTrue(matcher.matches(), "Invalid IPv4 address: {}", strIp); + return matchAddress(matcher); } /** - * 根据 ip/掩码位 计算IP段的起始IP(字符串型) - * 方法别名:inet_ntoa + * 根据 ip 和 掩码位 获取 子网的起始IP(字符串型) + *

方法别名:inet_ntoa

* - * @param ip 给定的IP,如218.240.38.69 - * @param maskBit 给定的掩码位,如30 + * @param ip 给定的IP,点分十进制,如:xxx.xxx.xxx.xxx + * @param maskBit 给定的掩码位,如:30 * @return 起始IP的字符串表示 */ public static String getBeginIpStr(final String ip, final int maskBit) { @@ -201,21 +262,22 @@ public class Ipv4Util { } /** - * 根据 ip/掩码位 计算IP段的起始IP(Long型) + * 根据 ip 和 掩码位 获取 子网的起始IP(Long型) * - * @param ip 给定的IP,如218.240.38.69 - * @param maskBit 给定的掩码位,如30 + * @param ip 给定的IP,点分十进制,如:xxx.xxx.xxx.xxx + * @param maskBit 给定的掩码位,如:30 * @return 起始IP的长整型表示 */ public static Long getBeginIpLong(final String ip, final int maskBit) { - return ipv4ToLong(ip) & ipv4ToLong(getMaskByMaskBit(maskBit)); + assertMaskBitValid(maskBit); + return ipv4ToLong(ip) & MaskBit.getMaskIpLong(maskBit); } /** - * 根据 ip/掩码位 计算IP段的终止IP(字符串型) + * 根据 ip 和 掩码位 获取 子网的终止IP(字符串型) * - * @param ip 给定的IP,如218.240.38.69 - * @param maskBit 给定的掩码位,如30 + * @param ip 给定的IP,点分十进制,如:xxx.xxx.xxx.xxx + * @param maskBit 给定的掩码位,如:30 * @return 终止IP的字符串表示 */ public static String getEndIpStr(final String ip, final int maskBit) { @@ -223,7 +285,18 @@ public class Ipv4Util { } /** - * 根据子网掩码转换为掩码位 + * 根据 ip 和 掩码位 获取 子网的终止IP(Long型) + * + * @param ip 给定的IP,点分十进制,如:xxx.xxx.xxx.xxx + * @param maskBit 给定的掩码位,如:30 + * @return 终止IP的长整型表示 + */ + public static Long getEndIpLong(final String ip, final int maskBit) { + return getBeginIpLong(ip, maskBit) + ~MaskBit.getMaskIpLong(maskBit); + } + + /** + * 将 子网掩码 转换为 掩码位 * * @param mask 掩码的点分十进制表示,例如 255.255.255.0 * @return 掩码位,例如 24 @@ -231,79 +304,86 @@ public class Ipv4Util { */ public static int getMaskBitByMask(final String mask) { final Integer maskBit = MaskBit.getMaskBit(mask); - if (maskBit == null) { - throw new IllegalArgumentException("Invalid netmask " + mask); - } + Assert.notNull(maskBit, "Invalid netmask:{}", mask); return maskBit; } /** - * 计算子网大小 + * 获取 子网内的 地址总数 * - * @param maskBit 掩码位 + * @param maskBit 掩码位,取值范围:[2, {@link #IP_MASK_MAX}] * @param isAll true:全量地址,false:可用地址 - * @return 地址总数 + * @return 子网内地址总数 */ public static int countByMaskBit(final int maskBit, final boolean isAll) { - //如果是可用地址的情况,掩码位小于等于0或大于等于32,则可用地址为0 - if ((false == isAll) && (maskBit <= 0 || maskBit >= 32)) { + assertMaskBitValid(maskBit); + //如果掩码位等于32,则可用地址为0 + if (maskBit == 32 && false == isAll) { return 0; } - final int count = (int) Math.pow(2, 32 - maskBit); + final int count = 1 << (32 - maskBit); return isAll ? count : count - 2; } /** - * 根据掩码位获取掩码 + * 根据 掩码位 获取 掩码地址 * - * @param maskBit 掩码位 - * @return 掩码 + * @param maskBit 掩码位,如:24,取值范围:[{@link #IP_MASK_MIN}, {@link #IP_MASK_MAX}] + * @return 掩码地址,点分十进制,如:255.255.255.0 */ public static String getMaskByMaskBit(final int maskBit) { return MaskBit.get(maskBit); } /** - * 根据开始IP与结束IP计算掩码 + * 根据 开始IP 与 结束IP 获取 掩码地址 * - * @param fromIp 开始IP - * @param toIp 结束IP - * @return 掩码x.x.x.x + * @param fromIp 开始IP,包含,点分十进制 + * @param toIp 结束IP,包含,点分十进制 + * @return 掩码地址,点分十进制 */ public static String getMaskByIpRange(final String fromIp, final String toIp) { final long toIpLong = ipv4ToLong(toIp); final long fromIpLong = ipv4ToLong(fromIp); - Assert.isTrue(fromIpLong < toIpLong, "to IP must be greater than from IP!"); + Assert.isTrue(fromIpLong <= toIpLong, "Start IP must be less than or equal to end IP!"); - final String[] fromIpSplit = StrUtil.splitToArray(fromIp, CharUtil.DOT); - final String[] toIpSplit = StrUtil.splitToArray(toIp, CharUtil.DOT); - final StringBuilder mask = new StringBuilder(); - for (int i = 0; i < toIpSplit.length; i++) { - mask.append(255 - Integer.parseInt(toIpSplit[i]) + Integer.parseInt(fromIpSplit[i])).append(CharUtil.DOT); - } - return mask.substring(0, mask.length() - 1); + return StrUtil.builder(15) + .append(255 - getPartOfIpLong(toIpLong, 1) + getPartOfIpLong(fromIpLong, 1)).append(CharUtil.DOT) + .append(255 - getPartOfIpLong(toIpLong, 2) + getPartOfIpLong(fromIpLong, 2)).append(CharUtil.DOT) + .append(255 - getPartOfIpLong(toIpLong, 3) + getPartOfIpLong(fromIpLong, 3)).append(CharUtil.DOT) + .append(255 - getPartOfIpLong(toIpLong, 4) + getPartOfIpLong(fromIpLong, 4)) + .toString(); } /** - * 计算IP区间有多少个IP + * 获得 指定区间内的 ip数量 * - * @param fromIp 开始IP - * @param toIp 结束IP + * @param fromIp 开始IP,包含,点分十进制 + * @param toIp 结束IP,包含,点分十进制 * @return IP数量 */ public static int countByIpRange(final String fromIp, final String toIp) { final long toIpLong = ipv4ToLong(toIp); final long fromIpLong = ipv4ToLong(fromIp); - if (fromIpLong > toIpLong) { - throw new IllegalArgumentException("to IP must be greater than from IP!"); - } + return countByIpRange(fromIpLong, toIpLong); + } + + /** + * 获得 指定区间内的 ip数量 + * + * @param fromIp 开始IP,包含 + * @param toIp 结束IP,包含 + * @return IP数量 + */ + public static int countByIpRange(final long fromIp, final long toIp) { + Assert.isTrue(fromIp <= toIp, "Start IP must be less than or equal to end IP!"); + int count = 1; - final int[] fromIpSplit = StrUtil.split(fromIp, CharUtil.DOT).stream().mapToInt(Integer::parseInt).toArray(); - final int[] toIpSplit = StrUtil.split(toIp, CharUtil.DOT).stream().mapToInt(Integer::parseInt).toArray(); - for (int i = fromIpSplit.length - 1; i >= 0; i--) { - count += (toIpSplit[i] - fromIpSplit[i]) * Math.pow(256, fromIpSplit.length - i - 1); - } + count += (getPartOfIpLong(toIp, 4) - getPartOfIpLong(fromIp, 4)); + count += (getPartOfIpLong(toIp, 3) - getPartOfIpLong(fromIp, 3)) << 8; + count += (getPartOfIpLong(toIp, 2) - getPartOfIpLong(fromIp, 2)) << 16; + count += (getPartOfIpLong(toIp, 1) - getPartOfIpLong(fromIp, 1)) << 24; return count; } @@ -320,11 +400,11 @@ public class Ipv4Util { /** * 判断掩码位是否合法 * - * @param maskBit 掩码位,例如 24 + * @param maskBit 掩码位,有效范围:[{@link #IP_MASK_MIN}, {@link #IP_MASK_MAX}] * @return true:掩码位合法;false:掩码位不合法 */ public static boolean isMaskBitValid(final int maskBit) { - return MaskBit.get(maskBit) != null; + return maskBit >= IP_MASK_MIN && maskBit <= IP_MASK_MAX; } /** @@ -337,66 +417,89 @@ public class Ipv4Util { * * 当然,还有127这个网段是环回地址 * - * @param ipAddress IP地址 + * @param ipAddress IP地址,点分十进制 * @return 是否为内网IP * @since 5.7.18 */ public static boolean isInnerIP(final String ipAddress) { - final boolean isInnerIp; final long ipNum = ipv4ToLong(ipAddress); - - final long aBegin = ipv4ToLong("10.0.0.0"); - final long aEnd = ipv4ToLong("10.255.255.255"); - - final long bBegin = ipv4ToLong("172.16.0.0"); - final long bEnd = ipv4ToLong("172.31.255.255"); - - final long cBegin = ipv4ToLong("192.168.0.0"); - final long cEnd = ipv4ToLong("192.168.255.255"); - - isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || LOCAL_IP.equals(ipAddress); - return isInnerIp; + return isBetween(ipNum, A_INNER_IP_LONG_BEGIN, A_INNER_IP_LONG_END) + || isBetween(ipNum, B_INNER_IP_LONG_BEGIN, B_INNER_IP_LONG_END) + || isBetween(ipNum, C_INNER_IP_LONG_BEGIN, C_INNER_IP_LONG_END) + || LOCAL_IP.equals(ipAddress); } //-------------------------------------------------------------------------------- Private method start /** - * 根据 ip/掩码位 计算IP段的终止IP(Long型) - * 注:此接口返回负数,请使用转成字符串后再转Long型 - * - * @param ip 给定的IP,如218.240.38.69 - * @param maskBit 给定的掩码位,如30 - * @return 终止IP的长整型表示 - */ - public static Long getEndIpLong(final String ip, final int maskBit) { - return getBeginIpLong(ip, maskBit) - + ~ipv4ToLong(getMaskByMaskBit(maskBit)); - } - - /** - * 将匹配到的Ipv4地址的4个分组分别处理 + * 将匹配到的Ipv4地址转为Long类型 * * @param matcher 匹配到的Ipv4正则 - * @return ipv4对应long + * @return ip的long值 */ private static long matchAddress(final Matcher matcher) { - long addr = 0; + int addr = 0; + // 每个点分十进制数字 转为 8位二进制 for (int i = 1; i <= 4; ++i) { - addr |= Long.parseLong(matcher.group(i)) << 8 * (4 - i); + addr <<= 8; + addr |= Integer.parseInt(matcher.group(i)); + } + // int的最高位无法直接使用,转为Long + if (addr < 0) { + return 0xffffffffL & addr; } return addr; } /** - * 指定IP的long是否在指定范围内 + * 指定IP是否在指定范围内 * * @param userIp 用户IP - * @param begin 开始IP - * @param end 结束IP + * @param begin 开始IP,包含 + * @param end 结束IP,包含 * @return 是否在范围内 */ - private static boolean isInner(final long userIp, final long begin, final long end) { + private static boolean isBetween(final long userIp, final long begin, final long end) { return (userIp >= begin) && (userIp <= end); } + + /** + * 校验 掩码位数,合法范围为:[1,32],不合法则抛出异常 + * + * @param maskBit 掩码位数 + */ + private static void assertMaskBitValid(final int maskBit) { + Assert.isTrue(isMaskBitValid(maskBit), "Invalid maskBit:{}", maskBit); + } + + /** + * 获取ip(Long类型)指定部分的十进制值,即,{@literal X.X.X.X }形式中每个部分的值 + *

例如,ip为{@literal 0xC0A802FA},第1部分的值为: + *

    + *
  • 第1部分的值为:@literal 0xC0},十进制值为:192
  • + *
  • 第2部分的值为:@literal 0xA8},十进制值为:168
  • + *
  • 第3部分的值为:@literal 0x02},十进制值为:2
  • + *
  • 第4部分的值为:@literal 0xFA},十进制值为:250
  • + *
+ *

+ * + * @param ip ip地址,Long类型 + * @param position 指定位置,取值范围:[1,4] + * @return ip地址指定部分的十进制值 + */ + private static int getPartOfIpLong(final long ip, final int position) { + switch (position) { + case 1: + return ((int) ip >> 24) & 0xFF; + case 2: + return ((int) ip >> 16) & 0xFF; + case 3: + return ((int) ip >> 8) & 0xFF; + case 4: + return ((int) ip) & 0xFF; + default: + throw new IllegalArgumentException("Illegal position of ip Long: " + position); + } + } //-------------------------------------------------------------------------------- Private method end } diff --git a/hutool-core/src/main/java/cn/hutool/core/net/MaskBit.java b/hutool-core/src/main/java/cn/hutool/core/net/MaskBit.java index 8e2cccc22..5b51c0c10 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/MaskBit.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/MaskBit.java @@ -1,5 +1,6 @@ package cn.hutool.core.net; +import cn.hutool.core.lang.Assert; import cn.hutool.core.map.BiMap; import java.util.HashMap; @@ -73,4 +74,15 @@ public class MaskBit { return MASK_BIT_MAP.getKey(mask); } + /** + * 根据掩码位获取掩码IP(Long型) + * + * @param maskBit 掩码位 + * @return 掩码IP(Long型) + * @since 6.0.0 + */ + public static long getMaskIpLong(final int maskBit) { + Assert.isTrue(MASK_BIT_MAP.containsKey(maskBit), "非法的掩码位数:{}", maskBit); + return -1L << (32 - maskBit); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/net/Ipv4UtilTest.java b/hutool-core/src/test/java/cn/hutool/core/net/Ipv4UtilTest.java index e98f646fa..97497d5b4 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/Ipv4UtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/Ipv4UtilTest.java @@ -4,8 +4,6 @@ import org.junit.Assert; import org.junit.Test; import org.junit.function.ThrowingRunnable; -import java.util.List; - public class Ipv4UtilTest { @Test @@ -28,10 +26,16 @@ public class Ipv4UtilTest { @Test public void longToIpTest() { - final String ip = "192.168.1.255"; - final long ipLong = Ipv4Util.ipv4ToLong(ip); - final String ipv4 = Ipv4Util.longToIpv4(ipLong); - Assert.assertEquals(ip, ipv4); + testLongToIp("192.168.1.255"); + testLongToIp("0.0.0.0"); + testLongToIp("0.0.0.255"); + testLongToIp("0.0.255.255"); + testLongToIp("0.255.255.255"); + testLongToIp("255.255.255.255"); + testLongToIp("255.255.255.0"); + testLongToIp("255.255.0.0"); + testLongToIp("255.0.0.0"); + testLongToIp("0.255.255.0"); } @Test @@ -44,9 +48,24 @@ public class Ipv4UtilTest { @Test public void listTest(){ - final int maskBit = Ipv4Util.getMaskBitByMask("255.255.255.0"); - final List list = Ipv4Util.list("192.168.100.2", maskBit, false); - Assert.assertEquals(254, list.size()); + final String ip = "192.168.100.2"; + testGenerateIpList(ip, 22, false); + testGenerateIpList(ip, 22, true); + + testGenerateIpList(ip, 24, false); + testGenerateIpList(ip, 24, true); + + testGenerateIpList(ip, 26, false); + testGenerateIpList(ip, 26, true); + + testGenerateIpList(ip, 30, false); + testGenerateIpList(ip, 30, true); + + testGenerateIpList(ip, 31, false); + testGenerateIpList(ip, 31, true); + + testGenerateIpList(ip, 32, false); + testGenerateIpList(ip, 32, true); testGenerateIpList("10.1.0.1", "10.2.1.2"); @@ -90,8 +109,9 @@ public class Ipv4UtilTest { @Test public void isMaskBitValidTest() { - final boolean maskBitValid = Ipv4Util.isMaskBitValid(32); - Assert.assertTrue("掩码位合法检验", maskBitValid); + for (int i = 1; i < 32; i++) { + Assert.assertTrue("掩码位非法:" + i, Ipv4Util.isMaskBitValid(i)); + } } @Test @@ -119,4 +139,19 @@ public class Ipv4UtilTest { Ipv4Util.list(fromIp, toIp).size() ); } + + @SuppressWarnings("SameParameterValue") + private void testGenerateIpList(final String ip, final int maskBit, final boolean isAll) { + Assert.assertEquals( + Ipv4Util.countByMaskBit(maskBit, isAll), + Ipv4Util.list(ip, maskBit, isAll).size() + ); + } + + private static void testLongToIp(final String ip){ + final long ipLong = Ipv4Util.ipv4ToLong(ip); + final String ipv4 = Ipv4Util.longToIpv4(ipLong); + Assert.assertEquals(ip, ipv4); + } + }