Browse Source

add Ipv4Util

Looly 5 years ago
parent
commit
0e049861ee

+ 2 - 1
CHANGELOG.md

@@ -3,7 +3,7 @@
 
 -------------------------------------------------------------------------------------------------------------
 
-# 5.4.1 (2020-08-20)
+# 5.4.1 (2020-08-24)
 
 ### 新特性
 * 【core  】     StrUtil增加firstNonXXX方法(issue#1020@Github)
@@ -14,6 +14,7 @@
 * 【core  】     增加PathUtil和FileNameUtil,分离FileUtil中部分方法
 * 【core  】     改造IndexedComparator,增加InstanceComparator
 * 【extra 】     增加CglibUtil
+* 【extra 】     增加Ipv4Util(pr#161@Gitee)
 
 ### Bug修复#
 * 【poi   】     修复ExcelBase.isXlsx方法判断问题(issue#I1S502@Gitee)

+ 296 - 409
hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java

@@ -1,440 +1,327 @@
 package cn.hutool.core.net;
 
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.StrUtil;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
- * IP地址工具类
+ * IPV4地址工具类
+ *
+ * <p>pr自:https://gitee.com/loolly/hutool/pulls/161</p>
  *
  * @author ZhuKun
- * @date 2020-08-21
+ * @since 5.4.1
  */
 public class Ipv4Util {
-    /**
-     * IP段的分割符
-     */
-    public static final String IP_SPLIT_MARK = "-";
-
-    /**
-     * IP与掩码的分割符
-     */
-    public static final String IP_MASK_SPLIT_MARK = "/";
+	/**
+	 * IP段的分割符
+	 */
+	public static final String IP_SPLIT_MARK = "-";
 
-    /**
-     * 最大掩码位
-     */
-    public static final int IP_MASK_MAX = 32;
+	/**
+	 * IP与掩码的分割符
+	 */
+	public static final String IP_MASK_SPLIT_MARK = "/";
 
-    /**
-     * 格式化IP段
-     *
-     * @param ip   IP地址
-     * @param mask 掩码
-     * @return 返回xxx.xxx.xxx.xxx/mask的格式
-     */
-    public static String formatIpBlock(String ip, String mask) {
-        return ip + IP_MASK_SPLIT_MARK + getMaskBitByMask(mask);
-    }
+	/**
+	 * 最大掩码位
+	 */
+	public static final int IP_MASK_MAX = 32;
 
-    /**
-     * 智能转换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集
-     */
-    public static List<String> list(String ipRange, boolean isAll) {
-        if (ipRange.contains(IP_SPLIT_MARK)) {
-            String[] range = ipRange.split(IP_SPLIT_MARK);
-            return list(range[0], range[1]);
-        } else if (ipRange.contains(IP_MASK_SPLIT_MARK)) {
-            String[] param = ipRange.split(IP_MASK_SPLIT_MARK);
-            return list(param[0], Integer.parseInt(param[1]), isAll);
-        } else {
-            List<String> ips = new ArrayList<>();
-            ips.add(ipRange);
-            return ips;
-        }
-    }
+	/**
+	 * 格式化IP段
+	 *
+	 * @param ip   IP地址
+	 * @param mask 掩码
+	 * @return 返回xxx.xxx.xxx.xxx/mask的格式
+	 */
+	public static String formatIpBlock(String ip, String mask) {
+		return ip + IP_MASK_SPLIT_MARK + getMaskBitByMask(mask);
+	}
 
-    /**
-     * 根据IP地址、子网掩码获取IP地址区间
-     *
-     * @param ip      IP地址
-     * @param maskBit 掩码位,例如24、32
-     * @param isAll   true:全量地址,false:可用地址
-     * @return
-     */
-    public static List<String> list(String ip, int maskBit, boolean isAll) {
-        List<String> list = new ArrayList<>();
-        if (maskBit == IP_MASK_MAX) {
-            if (Boolean.TRUE.equals(isAll)) {
-                list.add(ip);
-            }
-        } else {
-            String startIp = getBeginIpStr(ip, maskBit);
-            String endIp = getEndIpStr(ip, maskBit);
-            String subStart = startIp.split("\\.")[0] + "." + startIp.split("\\.")[1] + "." + startIp.split("\\.")[2] + ".";
-            String subEnd = endIp.split("\\.")[0] + "." + endIp.split("\\.")[1] + "." + endIp.split("\\.")[2] + ".";
-            if (Boolean.TRUE.equals(isAll)) {
-                startIp = subStart + (Integer.parseInt(startIp.split("\\.")[3]));
-                endIp = subEnd + (Integer.parseInt(endIp.split("\\.")[3]));
-            } else {
-                startIp = subStart + (Integer.parseInt(startIp.split("\\.")[3]) + 1);
-                endIp = subEnd + (Integer.parseInt(endIp.split("\\.")[3]) - 1);
-            }
-            list = list(startIp, endIp);
-        }
-        return list;
-    }
+	/**
+	 * 智能转换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集
+	 */
+	public static List<String> list(String ipRange, boolean isAll) {
+		if (ipRange.contains(IP_SPLIT_MARK)) {
+			String[] range = ipRange.split(IP_SPLIT_MARK);
+			return list(range[0], range[1]);
+		} else if (ipRange.contains(IP_MASK_SPLIT_MARK)) {
+			String[] param = ipRange.split(IP_MASK_SPLIT_MARK);
+			return list(param[0], Integer.parseInt(param[1]), isAll);
+		} else {
+			List<String> ips = new ArrayList<>();
+			ips.add(ipRange);
+			return ips;
+		}
+	}
 
-    /**
-     * 得到IP地址区间
-     *
-     * @param ipFrom 开始IP
-     * @param ipTo   结束IP
-     * @return
-     */
-    public static List<String> list(String ipFrom, String ipTo) {
-        List<String> ips = new ArrayList<>();
-        String[] ipfromd = ipFrom.split("\\.");
-        String[] iptod = ipTo.split("\\.");
-        int[] int_ipf = new int[4];
-        int[] int_ipt = new int[4];
-        for (int i = 0; i < 4; i++) {
-            int_ipf[i] = Integer.parseInt(ipfromd[i]);
-            int_ipt[i] = Integer.parseInt(iptod[i]);
-        }
-        for (int A = int_ipf[0]; A <= int_ipt[0]; A++) {
-            for (int B = (A == int_ipf[0] ? int_ipf[1] : 0); B <= (A == int_ipt[0] ? int_ipt[1]
-                    : 255); B++) {
-                for (int C = (B == int_ipf[1] ? int_ipf[2] : 0); C <= (B == int_ipt[1] ? int_ipt[2]
-                        : 255); C++) {
-                    for (int D = (C == int_ipf[2] ? int_ipf[3] : 0); D <= (C == int_ipt[2] ? int_ipt[3]
-                            : 255); D++) {
-                        ips.add(A + "." + B + "." + C + "." + D);
-                    }
-                }
-            }
-        }
-        return ips;
-    }
+	/**
+	 * 根据IP地址、子网掩码获取IP地址区间
+	 *
+	 * @param ip      IP地址
+	 * @param maskBit 掩码位,例如24、32
+	 * @param isAll   true:全量地址,false:可用地址
+	 * @return 区间地址
+	 */
+	public static List<String> list(String ip, int maskBit, boolean isAll) {
+		List<String> list = new ArrayList<>();
+		if (maskBit == IP_MASK_MAX) {
+			if (Boolean.TRUE.equals(isAll)) {
+				list.add(ip);
+			}
+		} else {
+			String startIp = getBeginIpStr(ip, maskBit);
+			String endIp = getEndIpStr(ip, maskBit);
+			String subStart = startIp.split("\\.")[0] + "." + startIp.split("\\.")[1] + "." + startIp.split("\\.")[2] + ".";
+			String subEnd = endIp.split("\\.")[0] + "." + endIp.split("\\.")[1] + "." + endIp.split("\\.")[2] + ".";
+			if (Boolean.TRUE.equals(isAll)) {
+				startIp = subStart + (Integer.parseInt(startIp.split("\\.")[3]));
+				endIp = subEnd + (Integer.parseInt(endIp.split("\\.")[3]));
+			} else {
+				startIp = subStart + (Integer.parseInt(startIp.split("\\.")[3]) + 1);
+				endIp = subEnd + (Integer.parseInt(endIp.split("\\.")[3]) - 1);
+			}
+			list = list(startIp, endIp);
+		}
+		return list;
+	}
 
-    /**
-     * 把long类型的Ip转为一般Ip类型:xx.xx.xx.xx
-     *
-     * @param ip
-     * @return
-     */
-    public static String longIpToStr(Long ip) {
-        String s1 = String.valueOf((ip & 4278190080L) / 16777216L);
-        String s2 = String.valueOf((ip & 16711680L) / 65536L);
-        String s3 = String.valueOf((ip & 65280L) / 256L);
-        String s4 = String.valueOf(ip & 255L);
-        return s1 + "." + s2 + "." + s3 + "." + s4;
-    }
+	/**
+	 * 得到IP地址区间
+	 *
+	 * @param ipFrom 开始IP
+	 * @param ipTo   结束IP
+	 * @return 区间地址
+	 */
+	public static List<String> list(String ipFrom, String ipTo) {
+		final int[] ipf = Convert.convert(int[].class, StrUtil.splitToArray(ipFrom, '.'));
+		final int[] ipt = Convert.convert(int[].class, StrUtil.splitToArray(ipTo, '.'));
 
-    /**
-     * 把xxx.xxx.xxx.xxx类型的转为long类型的IP
-     *
-     * @param ip 字符类型的IP
-     * @return
-     */
-    public static Long strIpToLong(String ip) {
-        Long ipLong = 0L;
-        String ipTemp = ip;
-        ipLong = ipLong * 256
-                + Long.parseLong(ipTemp.substring(0, ipTemp.indexOf(".")));
-        ipTemp = ipTemp.substring(ipTemp.indexOf(".") + 1);
-        ipLong = ipLong * 256
-                + Long.parseLong(ipTemp.substring(0, ipTemp.indexOf(".")));
-        ipTemp = ipTemp.substring(ipTemp.indexOf(".") + 1);
-        ipLong = ipLong * 256
-                + Long.parseLong(ipTemp.substring(0, ipTemp.indexOf(".")));
-        ipTemp = ipTemp.substring(ipTemp.indexOf(".") + 1);
-        ipLong = ipLong * 256 + Long.parseLong(ipTemp);
-        return ipLong;
-    }
+		final List<String> ips = new ArrayList<>();
+		for (int a = ipf[0]; a <= ipt[0]; a++) {
+			for (int b = (a == ipf[0] ? ipf[1] : 0); b <= (a == ipt[0] ? ipt[1]
+					: 255); b++) {
+				for (int c = (b == ipf[1] ? ipf[2] : 0); c <= (b == ipt[1] ? ipt[2]
+						: 255); c++) {
+					for (int d = (c == ipf[2] ? ipf[3] : 0); d <= (c == ipt[2] ? ipt[3]
+							: 255); d++) {
+						ips.add(a + "." + b + "." + c + "." + d);
+					}
+				}
+			}
+		}
+		return ips;
+	}
 
-    /**
-     * 根据掩码位获取掩码
-     *
-     * @param maskBit 掩码位数,如"28"、"30"
-     * @return
-     */
-    public static String getMaskByMaskBit(String maskBit) {
-        return StrUtil.isEmpty(maskBit) ? "error, maskBit is null !"
-                : maskBitMap().get(maskBit);
-    }
+	/**
+	 * 根据long值获取ip v4地址:xx.xx.xx.xx
+	 *
+	 * @param longIP IP的long表示形式
+	 * @return IP V4 地址
+	 */
+	public static String longToIpv4(long longIP) {
+		final StringBuilder sb = StrUtil.builder();
+		// 直接右移24位
+		sb.append((longIP >>> 24));
+		sb.append(".");
+		// 将高8位置0,然后右移16位
+		sb.append(((longIP & 0x00FFFFFF) >>> 16));
+		sb.append(".");
+		sb.append(((longIP & 0x0000FFFF) >>> 8));
+		sb.append(".");
+		sb.append((longIP & 0x000000FF));
+		return sb.toString();
+	}
 
-    /**
-     * 根据 ip/掩码位 计算IP段的起始IP(字符串型)
-     *
-     * @param ip      给定的IP,如218.240.38.69
-     * @param maskBit 给定的掩码位,如30
-     * @return 起始IP的字符串表示
-     */
-    public static String getBeginIpStr(String ip, int maskBit) {
-        return longIpToStr(getBeginIpLong(ip, maskBit));
-    }
+	/**
+	 * 根据ip地址(xxx.xxx.xxx.xxx)计算出long型的数据
+	 *
+	 * @param strIP IP V4 地址
+	 * @return long值
+	 */
+	public static long ipv4ToLong(String strIP) {
+		if (Validator.isIpv4(strIP)) {
+			long[] ip = new long[4];
+			// 先找到IP地址字符串中.的位置
+			int position1 = strIP.indexOf(".");
+			int position2 = strIP.indexOf(".", position1 + 1);
+			int position3 = strIP.indexOf(".", position2 + 1);
+			// 将每个.之间的字符串转换成整型
+			ip[0] = Long.parseLong(strIP.substring(0, position1));
+			ip[1] = Long.parseLong(strIP.substring(position1 + 1, position2));
+			ip[2] = Long.parseLong(strIP.substring(position2 + 1, position3));
+			ip[3] = Long.parseLong(strIP.substring(position3 + 1));
+			return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];
+		}
+		return 0;
+	}
 
-    /**
-     * 根据 ip/掩码位 计算IP段的起始IP(Long型)
-     *
-     * @param ip      给定的IP,如218.240.38.69
-     * @param maskBit 给定的掩码位,如30
-     * @return 起始IP的长整型表示
-     */
-    private static Long getBeginIpLong(String ip, int maskBit) {
-        return strIpToLong(ip) & strIpToLong(getMaskByMaskBit(maskBit));
-    }
+	/**
+	 * 根据 ip/掩码位 计算IP段的起始IP(字符串型)
+	 *
+	 * @param ip      给定的IP,如218.240.38.69
+	 * @param maskBit 给定的掩码位,如30
+	 * @return 起始IP的字符串表示
+	 */
+	public static String getBeginIpStr(String ip, int maskBit) {
+		return longToIpv4(getBeginIpLong(ip, maskBit));
+	}
 
-    /**
-     * 根据 ip/掩码位 计算IP段的终止IP(字符串型)
-     *
-     * @param ip      给定的IP,如218.240.38.69
-     * @param maskBit 给定的掩码位,如30
-     * @return 终止IP的字符串表示
-     */
-    public static String getEndIpStr(String ip, int maskBit) {
-        return longIpToStr(getEndIpLong(ip, maskBit));
-    }
+	/**
+	 * 根据 ip/掩码位 计算IP段的起始IP(Long型)
+	 *
+	 * @param ip      给定的IP,如218.240.38.69
+	 * @param maskBit 给定的掩码位,如30
+	 * @return 起始IP的长整型表示
+	 */
+	private static Long getBeginIpLong(String ip, int maskBit) {
+		return ipv4ToLong(ip) & ipv4ToLong(getMaskByMaskBit(maskBit));
+	}
 
-    /**
-     * 根据 ip/掩码位 计算IP段的终止IP(Long型)
-     * 注:此接口返回负数,请使用转成字符串后再转Long型
-     *
-     * @param ip      给定的IP,如218.240.38.69
-     * @param maskBit 给定的掩码位,如30
-     * @return 终止IP的长整型表示
-     */
-    private static Long getEndIpLong(String ip, int maskBit) {
-        return getBeginIpLong(ip, maskBit)
-                + ~strIpToLong(getMaskByMaskBit(maskBit));
-    }
+	/**
+	 * 根据 ip/掩码位 计算IP段的终止IP(字符串型)
+	 *
+	 * @param ip      给定的IP,如218.240.38.69
+	 * @param maskBit 给定的掩码位,如30
+	 * @return 终止IP的字符串表示
+	 */
+	public static String getEndIpStr(String ip, int maskBit) {
+		return longToIpv4(getEndIpLong(ip, maskBit));
+	}
 
+	/**
+	 * 根据子网掩码转换为掩码位
+	 *
+	 * @param mask 掩码,例如xxx.xxx.xxx.xxx
+	 * @return 掩码位,例如32
+	 */
+	public static int getMaskBitByMask(String mask) {
+		StringBuffer sbf;
+		String str;
+		int inetmask = 0;
+		int count;
+		for (String s : StrUtil.split(mask, ',')) {
+			sbf = toBin(Integer.parseInt(s));
+			str = sbf.reverse().toString();
+			count = 0;
+			for (int i = 0; i < str.length(); i++) {
+				i = str.indexOf('1', i);
+				if (i == -1) {
+					break;
+				}
+				count++;
+			}
+			inetmask += count;
+		}
+		return inetmask;
+	}
 
-    /**
-     * 根据子网掩码转换为掩码位
-     *
-     * @param mask 掩码,例如xxx.xxx.xxx.xxx
-     * @return 掩码位,例如32
-     */
-    public static int getMaskBitByMask(String mask) {
-        StringBuffer sbf;
-        String str;
-        int inetmask = 0, count = 0;
-        String[] ipList = mask.split("\\.");
-        for (int n = 0; n < ipList.length; n++) {
-            sbf = toBin(Integer.parseInt(ipList[n]));
-            str = sbf.reverse().toString();
-            count = 0;
-            for (int i = 0; i < str.length(); i++) {
-                i = str.indexOf('1', i);
-                if (i == -1) {
-                    break;
-                }
-                count++;
-            }
-            inetmask += count;
-        }
-        return inetmask;
-    }
+	/**
+	 * 计算子网大小
+	 *
+	 * @param maskBit 掩码位
+	 * @param isAll   true:全量地址,false:可用地址
+	 * @return 地址总数
+	 */
+	public static int countByMaskBit(int maskBit, boolean isAll) {
+		//如果是可用地址的情况,掩码位小于等于0或大于等于32,则可用地址为0
+		boolean isZero = !isAll && (maskBit <= 0 || maskBit >= 32);
+		if (isZero) {
+			return 0;
+		}
+		if (isAll) {
+			return (int) Math.pow(2, 32 - maskBit);
+		} else {
+			return (int) Math.pow(2, 32 - maskBit) - 2;
+		}
+	}
 
-    /**
-     * 计算子网大小
-     *
-     * @param maskBit 掩码位
-     * @param isAll   true:全量地址,false:可用地址
-     * @return 地址总数
-     */
-    public static int countByMaskBit(int maskBit, boolean isAll) {
-        //如果是可用地址的情况,掩码位小于等于0或大于等于32,则可用地址为0
-        boolean isZero = !isAll && (maskBit <= 0 || maskBit >= 32);
-        if (isZero) {
-            return 0;
-        }
-        if (isAll) {
-            return (int) Math.pow(2, 32 - maskBit);
-        } else {
-            return (int) Math.pow(2, 32 - maskBit) - 2;
-        }
-    }
+	/**
+	 * 根据掩码位获取掩码
+	 *
+	 * @param maskBit 掩码位
+	 * @return 掩码
+	 */
+	public static String getMaskByMaskBit(int maskBit) {
+		return MaskBit.get(maskBit);
+	}
 
-    private static StringBuffer toBin(int x) {
-        StringBuffer result = new StringBuffer();
-        result.append(x % 2);
-        x /= 2;
-        while (x > 0) {
-            result.append(x % 2);
-            x /= 2;
-        }
-        return result;
-    }
+	/**
+	 * 根据开始IP与结束IP计算掩码
+	 *
+	 * @param fromIp 开始IP
+	 * @param toIp   结束IP
+	 * @return 掩码x.x.x.x
+	 */
+	public static String getMaskByIpRange(String fromIp, String toIp) {
+		long toIpLong = ipv4ToLong(toIp);
+		long fromIpLong = ipv4ToLong(fromIp);
+		if (fromIpLong > toIpLong) {
+			throw new IllegalArgumentException("to IP must be greater than from IP!");
+		}
+		String[] fromIpSplit = StrUtil.splitToArray(fromIp, '.');
+		String[] toIpSplit = StrUtil.splitToArray(toIp, '.');
+		StringBuilder mask = new StringBuilder();
+		for (int i = 0; i < toIpSplit.length; i++) {
+			mask.append(255 - Integer.parseInt(toIpSplit[i]) + Integer.parseInt(fromIpSplit[i])).append(".");
+		}
+		return mask.substring(0, mask.length() - 1);
+	}
 
-    /**
-     * 存储着所有的掩码位及对应的掩码 key:掩码位 value:掩码(x.x.x.x)
-     *
-     * @return
-     */
-    private static Map<String, String> maskBitMap() {
-        Map<String, String> maskBit = new HashMap<>(32);
-        maskBit.put("1", "128.0.0.0");
-        maskBit.put("2", "192.0.0.0");
-        maskBit.put("3", "224.0.0.0");
-        maskBit.put("4", "240.0.0.0");
-        maskBit.put("5", "248.0.0.0");
-        maskBit.put("6", "252.0.0.0");
-        maskBit.put("7", "254.0.0.0");
-        maskBit.put("8", "255.0.0.0");
-        maskBit.put("9", "255.128.0.0");
-        maskBit.put("10", "255.192.0.0");
-        maskBit.put("11", "255.224.0.0");
-        maskBit.put("12", "255.240.0.0");
-        maskBit.put("13", "255.248.0.0");
-        maskBit.put("14", "255.252.0.0");
-        maskBit.put("15", "255.254.0.0");
-        maskBit.put("16", "255.255.0.0");
-        maskBit.put("17", "255.255.128.0");
-        maskBit.put("18", "255.255.192.0");
-        maskBit.put("19", "255.255.224.0");
-        maskBit.put("20", "255.255.240.0");
-        maskBit.put("21", "255.255.248.0");
-        maskBit.put("22", "255.255.252.0");
-        maskBit.put("23", "255.255.254.0");
-        maskBit.put("24", "255.255.255.0");
-        maskBit.put("25", "255.255.255.128");
-        maskBit.put("26", "255.255.255.192");
-        maskBit.put("27", "255.255.255.224");
-        maskBit.put("28", "255.255.255.240");
-        maskBit.put("29", "255.255.255.248");
-        maskBit.put("30", "255.255.255.252");
-        maskBit.put("31", "255.255.255.254");
-        maskBit.put("32", "255.255.255.255");
-        return maskBit;
-    }
+	/**
+	 * 计算IP区间有多少个IP
+	 *
+	 * @param fromIp 开始IP
+	 * @param toIp   结束IP
+	 * @return IP数量
+	 */
+	public static int countByIpRange(String fromIp, String toIp) {
+		long toIpLong = ipv4ToLong(toIp);
+		long fromIpLong = ipv4ToLong(fromIp);
+		if (fromIpLong > toIpLong) {
+			throw new IllegalArgumentException("to IP must be greater than from IP!");
+		}
+		int count = 1;
+		int[] fromIpSplit = StrUtil.split(fromIp, '.').stream().mapToInt(Integer::parseInt).toArray();
+		int[] toIpSplit = StrUtil.split(toIp, '.').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);
+		}
+		return count;
+	}
 
-    /**
-     * 根据掩码位获取掩码
-     *
-     * @param maskBit
-     * @return
-     */
-    public static String getMaskByMaskBit(int maskBit) {
-        switch (maskBit) {
-            case 1:
-                return "128.0.0.0";
-            case 2:
-                return "192.0.0.0";
-            case 3:
-                return "224.0.0.0";
-            case 4:
-                return "240.0.0.0";
-            case 5:
-                return "248.0.0.0";
-            case 6:
-                return "252.0.0.0";
-            case 7:
-                return "254.0.0.0";
-            case 8:
-                return "255.0.0.0";
-            case 9:
-                return "255.128.0.0";
-            case 10:
-                return "255.192.0.0";
-            case 11:
-                return "255.224.0.0";
-            case 12:
-                return "255.240.0.0";
-            case 13:
-                return "255.248.0.0";
-            case 14:
-                return "255.252.0.0";
-            case 15:
-                return "255.254.0.0";
-            case 16:
-                return "255.255.0.0";
-            case 17:
-                return "255.255.128.0";
-            case 18:
-                return "255.255.192.0";
-            case 19:
-                return "255.255.224.0";
-            case 20:
-                return "255.255.240.0";
-            case 21:
-                return "255.255.248.0";
-            case 22:
-                return "255.255.252.0";
-            case 23:
-                return "255.255.254.0";
-            case 24:
-                return "255.255.255.0";
-            case 25:
-                return "255.255.255.128";
-            case 26:
-                return "255.255.255.192";
-            case 27:
-                return "255.255.255.224";
-            case 28:
-                return "255.255.255.240";
-            case 29:
-                return "255.255.255.248";
-            case 30:
-                return "255.255.255.252";
-            case 31:
-                return "255.255.255.254";
-            case 32:
-                return "255.255.255.255";
-            default:
-                return "";
-        }
-    }
+	//-------------------------------------------------------------------------------- Private method start
 
-    /**
-     * 根据开始IP与结束IP计算掩码
-     *
-     * @param fromIp 开始IP
-     * @param toIp   结束IP
-     * @return 掩码x.x.x.x
-     * @throws Exception
-     */
-    public static String getMaskByIpRange(String fromIp, String toIp) throws Exception {
-        Long toIpLong = strIpToLong(toIp);
-        Long fromIpLong = strIpToLong(fromIp);
-        if (fromIpLong > toIpLong) {
-            throw new Exception("开始IP大与结束IP");
-        }
-        String[] fromIpSplit = fromIp.split("\\.");
-        String[] toIpSplit = toIp.split("\\.");
-        StringBuilder mask = new StringBuilder();
-        for (int i = 0; i < toIpSplit.length; i++) {
-            mask.append(255 - Integer.parseInt(toIpSplit[i]) + Integer.parseInt(fromIpSplit[i])).append(".");
-        }
-        return mask.substring(0, mask.length() - 1);
-    }
+	/**
+	 * 根据 ip/掩码位 计算IP段的终止IP(Long型)
+	 * 注:此接口返回负数,请使用转成字符串后再转Long型
+	 *
+	 * @param ip      给定的IP,如218.240.38.69
+	 * @param maskBit 给定的掩码位,如30
+	 * @return 终止IP的长整型表示
+	 */
+	private static Long getEndIpLong(String ip, int maskBit) {
+		return getBeginIpLong(ip, maskBit)
+				+ ~ipv4ToLong(getMaskByMaskBit(maskBit));
+	}
 
-    /**
-     * 计算IP区间有多少个IP
-     *
-     * @param fromIp 开始IP
-     * @param toIp   结束IP
-     * @return IP数量
-     * @throws Exception
-     */
-    public static int countByIpRange(String fromIp, String toIp) throws Exception {
-        Long toIpLong = strIpToLong(toIp);
-        Long fromIpLong = strIpToLong(fromIp);
-        if (fromIpLong > toIpLong) {
-            throw new Exception("开始IP大与结束IP");
-        }
-        int count = 1;
-        int[] fromIpSplit = Arrays.stream(fromIp.split("\\.")).mapToInt(Integer::parseInt).toArray();
-        int[] toIpSplit = Arrays.stream(toIp.split("\\.")).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);
-        }
-        return count;
-    }
+	private static StringBuffer toBin(int x) {
+		StringBuffer result = new StringBuffer();
+		result.append(x % 2);
+		x /= 2;
+		while (x > 0) {
+			result.append(x % 2);
+			x /= 2;
+		}
+		return result;
+	}
+	//-------------------------------------------------------------------------------- Private method end
 }

+ 60 - 0
hutool-core/src/main/java/cn/hutool/core/net/MaskBit.java

@@ -0,0 +1,60 @@
+package cn.hutool.core.net;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 掩码位和掩码之间的Map对应
+ *
+ * @since 5.4.1
+ * @author looly
+ */
+public class MaskBit {
+
+	private static final Map<Integer, String> maskBitMap;
+	static {
+		maskBitMap = new HashMap<>(32);
+		maskBitMap.put(1, "128.0.0.0");
+		maskBitMap.put(2, "192.0.0.0");
+		maskBitMap.put(3, "224.0.0.0");
+		maskBitMap.put(4, "240.0.0.0");
+		maskBitMap.put(5, "248.0.0.0");
+		maskBitMap.put(6, "252.0.0.0");
+		maskBitMap.put(7, "254.0.0.0");
+		maskBitMap.put(8, "255.0.0.0");
+		maskBitMap.put(9, "255.128.0.0");
+		maskBitMap.put(10, "255.192.0.0");
+		maskBitMap.put(11, "255.224.0.0");
+		maskBitMap.put(12, "255.240.0.0");
+		maskBitMap.put(13, "255.248.0.0");
+		maskBitMap.put(14, "255.252.0.0");
+		maskBitMap.put(15, "255.254.0.0");
+		maskBitMap.put(16, "255.255.0.0");
+		maskBitMap.put(17, "255.255.128.0");
+		maskBitMap.put(18, "255.255.192.0");
+		maskBitMap.put(19, "255.255.224.0");
+		maskBitMap.put(20, "255.255.240.0");
+		maskBitMap.put(21, "255.255.248.0");
+		maskBitMap.put(22, "255.255.252.0");
+		maskBitMap.put(23, "255.255.254.0");
+		maskBitMap.put(24, "255.255.255.0");
+		maskBitMap.put(25, "255.255.255.128");
+		maskBitMap.put(26, "255.255.255.192");
+		maskBitMap.put(27, "255.255.255.224");
+		maskBitMap.put(28, "255.255.255.240");
+		maskBitMap.put(29, "255.255.255.248");
+		maskBitMap.put(30, "255.255.255.252");
+		maskBitMap.put(31, "255.255.255.254");
+		maskBitMap.put(32, "255.255.255.255");
+	}
+
+	/**
+	 * 根据掩码位获取掩码
+	 *
+	 * @param maskBit 掩码位
+	 * @return 掩码
+	 */
+	public static String get(int maskBit) {
+		return maskBitMap.get(maskBit);
+	}
+}

+ 4 - 26
hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java

@@ -5,7 +5,6 @@ import cn.hutool.core.exceptions.UtilException;
 import cn.hutool.core.io.IORuntimeException;
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.lang.Filter;
-import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
 
@@ -58,19 +57,10 @@ public class NetUtil {
 	 *
 	 * @param longIP IP的long表示形式
 	 * @return IP V4 地址
+	 * @see Ipv4Util#longToIpv4(long)
 	 */
 	public static String longToIpv4(long longIP) {
-		final StringBuilder sb = StrUtil.builder();
-		// 直接右移24位
-		sb.append((longIP >>> 24));
-		sb.append(".");
-		// 将高8位置0,然后右移16位
-		sb.append(((longIP & 0x00FFFFFF) >>> 16));
-		sb.append(".");
-		sb.append(((longIP & 0x0000FFFF) >>> 8));
-		sb.append(".");
-		sb.append((longIP & 0x000000FF));
-		return sb.toString();
+		return Ipv4Util.longToIpv4(longIP);
 	}
 
 	/**
@@ -78,22 +68,10 @@ public class NetUtil {
 	 *
 	 * @param strIP IP V4 地址
 	 * @return long值
+	 * @see Ipv4Util#ipv4ToLong(String)
 	 */
 	public static long ipv4ToLong(String strIP) {
-		if (Validator.isIpv4(strIP)) {
-			long[] ip = new long[4];
-			// 先找到IP地址字符串中.的位置
-			int position1 = strIP.indexOf(".");
-			int position2 = strIP.indexOf(".", position1 + 1);
-			int position3 = strIP.indexOf(".", position2 + 1);
-			// 将每个.之间的字符串转换成整型
-			ip[0] = Long.parseLong(strIP.substring(0, position1));
-			ip[1] = Long.parseLong(strIP.substring(position1 + 1, position2));
-			ip[2] = Long.parseLong(strIP.substring(position2 + 1, position3));
-			ip[3] = Long.parseLong(strIP.substring(position3 + 1));
-			return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];
-		}
-		return 0;
+		return Ipv4Util.ipv4ToLong(strIP);
 	}
 
 	/**

+ 3 - 2
hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java

@@ -92,10 +92,11 @@ public class ThreadUtil {
 	 * 获得一个新的线程池,并指定最大任务队列大小<br>
 	 * 如果maximumPoolSize &gt;= corePoolSize,在没有新任务加入的情况下,多出的线程将最多保留60s
 	 *
-	 * @param corePoolSize    初始线程池大小
-	 * @param maximumPoolSize 最大线程池大小
+	 * @param corePoolSize     初始线程池大小
+	 * @param maximumPoolSize  最大线程池大小
 	 * @param maximumQueueSize 最大任务队列大小
 	 * @return {@link ThreadPoolExecutor}
+	 * @since 5.4.1
 	 */
 	public static ExecutorService newExecutor(int corePoolSize, int maximumPoolSize, int maximumQueueSize) {
 		return ExecutorBuilder.create()