mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
!938 优化Ipv4Util
Merge pull request !938 from emptypoint/fix-doc-Ipv4Util
This commit is contained in:
commit
50de1b6da4
@ -1,11 +1,10 @@
|
|||||||
package cn.hutool.core.net;
|
package cn.hutool.core.net;
|
||||||
|
|
||||||
import cn.hutool.core.collection.ListUtil;
|
import cn.hutool.core.collection.ListUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.regex.PatternPool;
|
import cn.hutool.core.regex.PatternPool;
|
||||||
import cn.hutool.core.util.CharUtil;
|
|
||||||
import cn.hutool.core.text.StrUtil;
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
import cn.hutool.core.util.CharUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -17,7 +16,19 @@ import java.util.regex.Matcher;
|
|||||||
*
|
*
|
||||||
* <p>pr自:https://gitee.com/loolly/hutool/pulls/161</p>
|
* <p>pr自:https://gitee.com/loolly/hutool/pulls/161</p>
|
||||||
*
|
*
|
||||||
|
* <p>名词解释:
|
||||||
|
* <ul>
|
||||||
|
* <li>ip字符串:点分十进制,形如:xxx.xxx.xxx.xxx</li>
|
||||||
|
* <li>ip的Long类型:有效位32位,每8位可以转为一个十进制数,例如:0xC0A802FA, 转为点分十进制是:192.168.2.250</li>
|
||||||
|
* <li>掩码地址:点分十进制,例如:255.255.255.0</li>
|
||||||
|
* <li>掩码位:int类型,例如 24, 它代表的掩码地址为:255.255.255.0;掩码位和掩码地址的相互转换,请使用 {@link MaskBit}</li>
|
||||||
|
* <li>CIDR:无类域间路由,形如:xxx.xxx.xxx.xxx/掩码位</li>
|
||||||
|
* <li>全量地址:区间内所有ip地址,包含区间两端</li>
|
||||||
|
* <li>可用地址:区间内所有ip地址,但是不包含区间两端</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
* @author ZhuKun
|
* @author ZhuKun
|
||||||
|
* @author emptypoint
|
||||||
* @since 5.4.1
|
* @since 5.4.1
|
||||||
*/
|
*/
|
||||||
public class Ipv4Util {
|
public class Ipv4Util {
|
||||||
@ -43,22 +54,57 @@ public class Ipv4Util {
|
|||||||
public static final int IP_MASK_MAX = 32;
|
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 ip IP地址,点分十进制,如:xxx.xxx.xxx.xxx
|
||||||
* @param mask 掩码
|
* @param mask 掩码地址,点分十进制,如:255.255.255.0
|
||||||
* @return 返回xxx.xxx.xxx.xxx/mask的格式
|
* @return 返回 {@literal xxx.xxx.xxx.xxx/掩码位} 的格式
|
||||||
*/
|
*/
|
||||||
public static String formatIpBlock(final String ip, final String mask) {
|
public static String formatIpBlock(final String ip, final String mask) {
|
||||||
return ip + IP_MASK_SPLIT_MARK + getMaskBitByMask(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 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时才生效
|
* @param isAll true:全量地址,false:可用地址;该参数仅在ipRange为X.X.X.X/X时才生效
|
||||||
* @return IP集
|
* @return 区间内的所有IP地址,点分十进制格式
|
||||||
*/
|
*/
|
||||||
public static List<String> list(final String ipRange, final boolean isAll) {
|
public static List<String> list(final String ipRange, final boolean isAll) {
|
||||||
if (ipRange.contains(IP_SPLIT_MARK)) {
|
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 maskBit 掩码位,例如24、32
|
||||||
* @param isAll true:全量地址,false:可用地址
|
* @param isAll true:全量地址,false:可用地址
|
||||||
* @return 区间地址
|
* @return 子网所有ip地址
|
||||||
*/
|
*/
|
||||||
public static List<String> list(final String ip, final int maskBit, final boolean isAll) {
|
public static List<String> 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) {
|
if (maskBit == IP_MASK_MAX) {
|
||||||
final List<String> list = new ArrayList<>();
|
final List<String> list = new ArrayList<>(isAll ? 1 : 0);
|
||||||
if (isAll) {
|
if (isAll) {
|
||||||
list.add(ip);
|
list.add(ip);
|
||||||
}
|
}
|
||||||
@ -97,6 +149,7 @@ public class Ipv4Util {
|
|||||||
return list(startIp, endIp);
|
return list(startIp, endIp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 可用地址,排除开始和结束的地址
|
||||||
int lastDotIndex = startIp.lastIndexOf(CharUtil.DOT) + 1;
|
int lastDotIndex = startIp.lastIndexOf(CharUtil.DOT) + 1;
|
||||||
startIp = StrUtil.subPre(startIp, lastDotIndex) +
|
startIp = StrUtil.subPre(startIp, lastDotIndex) +
|
||||||
(Integer.parseInt(Objects.requireNonNull(StrUtil.subSuf(startIp, lastDotIndex))) + 1);
|
(Integer.parseInt(Objects.requireNonNull(StrUtil.subSuf(startIp, lastDotIndex))) + 1);
|
||||||
@ -107,17 +160,26 @@ public class Ipv4Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 得到IP地址区间
|
* 获得 指定区间内 所有ip地址
|
||||||
*
|
*
|
||||||
* @param ipFrom 开始IP
|
* @param ipFrom 开始IP,包含,点分十进制
|
||||||
* @param ipTo 结束IP
|
* @param ipTo 结束IP,包含,点分十进制
|
||||||
* @return 区间地址
|
* @return 区间内所有ip地址
|
||||||
*/
|
*/
|
||||||
public static List<String> list(final String ipFrom, final String ipTo) {
|
public static List<String> 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<String> list(final long ipFrom, final long ipTo) {
|
||||||
// 确定ip数量
|
// 确定ip数量
|
||||||
final int count = countByIpRange(ipFrom, ipTo);
|
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<String> ips = new ArrayList<>(count);
|
final List<String> ips = new ArrayList<>(count);
|
||||||
// 是否是循环的第一个值
|
// 是否是循环的第一个值
|
||||||
@ -125,24 +187,30 @@ public class Ipv4Util {
|
|||||||
// 是否是循环的最后一个值
|
// 是否是循环的最后一个值
|
||||||
boolean aIsEnd, bIsEnd, cIsEnd;
|
boolean aIsEnd, bIsEnd, cIsEnd;
|
||||||
// 循环的结束值
|
// 循环的结束值
|
||||||
final int aEnd = to[0];
|
final int aEnd = getPartOfIpLong(ipTo, 1);
|
||||||
int bEnd;
|
int bEnd;
|
||||||
int cEnd;
|
int cEnd;
|
||||||
int dEnd;
|
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);
|
aIsEnd = (a == aEnd);
|
||||||
// 本次循环的结束结束值
|
// 本次循环的结束结束值
|
||||||
bEnd = aIsEnd ? to[1] : 255;
|
bEnd = aIsEnd ? getPartOfIpLong(ipTo, 2) : 255;
|
||||||
for (int b = (aIsStart ? from[1] : 0); b <= bEnd; b++) {
|
for (int b = (aIsStart ? getPartOfIpLong(ipFrom, 2) : 0); b <= bEnd; b++) {
|
||||||
// 在上一个循环是最后值的基础上进行判断
|
// 在上一个循环是最后值的基础上进行判断
|
||||||
bIsEnd = aIsEnd && (b == bEnd);
|
bIsEnd = aIsEnd && (b == bEnd);
|
||||||
cEnd = bIsEnd ? to[2] : 255;
|
cEnd = bIsEnd ? getPartOfIpLong(ipTo, 3) : 255;
|
||||||
for (int c = (bIsStart ? from[2] : 0); c <= cEnd; c++) {
|
for (int c = (bIsStart ? getPartOfIpLong(ipFrom, 3) : 0); c <= cEnd; c++) {
|
||||||
// 在之前循环是最后值的基础上进行判断
|
// 在之前循环是最后值的基础上进行判断
|
||||||
cIsEnd = bIsEnd && (c == cEnd);
|
cIsEnd = bIsEnd && (c == cEnd);
|
||||||
dEnd = cIsEnd ? to[3] : 255;
|
dEnd = cIsEnd ? getPartOfIpLong(ipTo, 4) : 255;
|
||||||
for (int d = (cIsStart ? from[3] : 0); d <= dEnd; d++) {
|
for (int d = (cIsStart ? getPartOfIpLong(ipFrom, 4) : 0); d <= dEnd; d++) {
|
||||||
ips.add(a + "." + b + "." + c + "." + 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;
|
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表示形式
|
* @param longIp IP的long表示形式
|
||||||
* @return IP V4 地址
|
* @return 点分十进制ip地址
|
||||||
*/
|
*/
|
||||||
public static String longToIpv4(final long longIP) {
|
public static String longToIpv4(final long longIp) {
|
||||||
final StringBuilder sb = StrUtil.builder();
|
return StrUtil.builder(15)
|
||||||
// 直接右移24位
|
.append(getPartOfIpLong(longIp, 1)).append(CharUtil.DOT)
|
||||||
sb.append(longIP >> 24 & 0xFF);
|
.append(getPartOfIpLong(longIp, 2)).append(CharUtil.DOT)
|
||||||
sb.append(CharUtil.DOT);
|
.append(getPartOfIpLong(longIp, 3)).append(CharUtil.DOT)
|
||||||
// 将高8位置0,然后右移16位
|
.append(getPartOfIpLong(longIp, 4))
|
||||||
sb.append(longIP >> 16 & 0xFF);
|
.toString();
|
||||||
sb.append(CharUtil.DOT);
|
|
||||||
sb.append(longIP >> 8 & 0xFF);
|
|
||||||
sb.append(CharUtil.DOT);
|
|
||||||
sb.append(longIP & 0xFF);
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据ip地址(xxx.xxx.xxx.xxx)计算出long型的数据
|
* 将 ip字符串 转换为 long值
|
||||||
* 方法别名:inet_aton
|
* <p>方法别名:inet_aton</p>
|
||||||
*
|
*
|
||||||
* @param strIP IP V4 地址
|
* @param strIp ip地址,点分十进制,xxx.xxx.xxx.xxx
|
||||||
* @return long值
|
* @return ip的long值
|
||||||
*/
|
*/
|
||||||
public static long ipv4ToLong(final String strIP) {
|
public static long ipv4ToLong(final String strIp) {
|
||||||
final Matcher matcher = PatternPool.IPV4.matcher(strIP);
|
final Matcher matcher = PatternPool.IPV4.matcher(strIp);
|
||||||
if (matcher.matches()) {
|
Assert.isTrue(matcher.matches(), "Invalid IPv4 address: {}", strIp);
|
||||||
return matchAddress(matcher);
|
return matchAddress(matcher);
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Invalid IPv4 address!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 ip/掩码位 计算IP段的起始IP(字符串型)
|
* 根据 ip 和 掩码位 获取 子网的起始IP(字符串型)
|
||||||
* 方法别名:inet_ntoa
|
* <p>方法别名:inet_ntoa</p>
|
||||||
*
|
*
|
||||||
* @param ip 给定的IP,如218.240.38.69
|
* @param ip 给定的IP,点分十进制,如:xxx.xxx.xxx.xxx
|
||||||
* @param maskBit 给定的掩码位,如30
|
* @param maskBit 给定的掩码位,如:30
|
||||||
* @return 起始IP的字符串表示
|
* @return 起始IP的字符串表示
|
||||||
*/
|
*/
|
||||||
public static String getBeginIpStr(final String ip, final int maskBit) {
|
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 ip 给定的IP,点分十进制,如:xxx.xxx.xxx.xxx
|
||||||
* @param maskBit 给定的掩码位,如30
|
* @param maskBit 给定的掩码位,如:30
|
||||||
* @return 起始IP的长整型表示
|
* @return 起始IP的长整型表示
|
||||||
*/
|
*/
|
||||||
public static Long getBeginIpLong(final String ip, final int maskBit) {
|
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 ip 给定的IP,点分十进制,如:xxx.xxx.xxx.xxx
|
||||||
* @param maskBit 给定的掩码位,如30
|
* @param maskBit 给定的掩码位,如:30
|
||||||
* @return 终止IP的字符串表示
|
* @return 终止IP的字符串表示
|
||||||
*/
|
*/
|
||||||
public static String getEndIpStr(final String ip, final int maskBit) {
|
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
|
* @param mask 掩码的点分十进制表示,例如 255.255.255.0
|
||||||
* @return 掩码位,例如 24
|
* @return 掩码位,例如 24
|
||||||
@ -231,79 +304,86 @@ public class Ipv4Util {
|
|||||||
*/
|
*/
|
||||||
public static int getMaskBitByMask(final String mask) {
|
public static int getMaskBitByMask(final String mask) {
|
||||||
final Integer maskBit = MaskBit.getMaskBit(mask);
|
final Integer maskBit = MaskBit.getMaskBit(mask);
|
||||||
if (maskBit == null) {
|
Assert.notNull(maskBit, "Invalid netmask:{}", mask);
|
||||||
throw new IllegalArgumentException("Invalid netmask " + mask);
|
|
||||||
}
|
|
||||||
return maskBit;
|
return maskBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算子网大小
|
* 获取 子网内的 地址总数
|
||||||
*
|
*
|
||||||
* @param maskBit 掩码位
|
* @param maskBit 掩码位,取值范围:[2, {@link #IP_MASK_MAX}]
|
||||||
* @param isAll true:全量地址,false:可用地址
|
* @param isAll true:全量地址,false:可用地址
|
||||||
* @return 地址总数
|
* @return 子网内地址总数
|
||||||
*/
|
*/
|
||||||
public static int countByMaskBit(final int maskBit, final boolean isAll) {
|
public static int countByMaskBit(final int maskBit, final boolean isAll) {
|
||||||
//如果是可用地址的情况,掩码位小于等于0或大于等于32,则可用地址为0
|
assertMaskBitValid(maskBit);
|
||||||
if ((false == isAll) && (maskBit <= 0 || maskBit >= 32)) {
|
//如果掩码位等于32,则可用地址为0
|
||||||
|
if (maskBit == 32 && false == isAll) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int count = (int) Math.pow(2, 32 - maskBit);
|
final int count = 1 << (32 - maskBit);
|
||||||
return isAll ? count : count - 2;
|
return isAll ? count : count - 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据掩码位获取掩码
|
* 根据 掩码位 获取 掩码地址
|
||||||
*
|
*
|
||||||
* @param maskBit 掩码位
|
* @param maskBit 掩码位,如:24,取值范围:[{@link #IP_MASK_MIN}, {@link #IP_MASK_MAX}]
|
||||||
* @return 掩码
|
* @return 掩码地址,点分十进制,如:255.255.255.0
|
||||||
*/
|
*/
|
||||||
public static String getMaskByMaskBit(final int maskBit) {
|
public static String getMaskByMaskBit(final int maskBit) {
|
||||||
return MaskBit.get(maskBit);
|
return MaskBit.get(maskBit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据开始IP与结束IP计算掩码
|
* 根据 开始IP 与 结束IP 获取 掩码地址
|
||||||
*
|
*
|
||||||
* @param fromIp 开始IP
|
* @param fromIp 开始IP,包含,点分十进制
|
||||||
* @param toIp 结束IP
|
* @param toIp 结束IP,包含,点分十进制
|
||||||
* @return 掩码x.x.x.x
|
* @return 掩码地址,点分十进制
|
||||||
*/
|
*/
|
||||||
public static String getMaskByIpRange(final String fromIp, final String toIp) {
|
public static String getMaskByIpRange(final String fromIp, final String toIp) {
|
||||||
final long toIpLong = ipv4ToLong(toIp);
|
final long toIpLong = ipv4ToLong(toIp);
|
||||||
final long fromIpLong = ipv4ToLong(fromIp);
|
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);
|
return StrUtil.builder(15)
|
||||||
final String[] toIpSplit = StrUtil.splitToArray(toIp, CharUtil.DOT);
|
.append(255 - getPartOfIpLong(toIpLong, 1) + getPartOfIpLong(fromIpLong, 1)).append(CharUtil.DOT)
|
||||||
final StringBuilder mask = new StringBuilder();
|
.append(255 - getPartOfIpLong(toIpLong, 2) + getPartOfIpLong(fromIpLong, 2)).append(CharUtil.DOT)
|
||||||
for (int i = 0; i < toIpSplit.length; i++) {
|
.append(255 - getPartOfIpLong(toIpLong, 3) + getPartOfIpLong(fromIpLong, 3)).append(CharUtil.DOT)
|
||||||
mask.append(255 - Integer.parseInt(toIpSplit[i]) + Integer.parseInt(fromIpSplit[i])).append(CharUtil.DOT);
|
.append(255 - getPartOfIpLong(toIpLong, 4) + getPartOfIpLong(fromIpLong, 4))
|
||||||
}
|
.toString();
|
||||||
return mask.substring(0, mask.length() - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算IP区间有多少个IP
|
* 获得 指定区间内的 ip数量
|
||||||
*
|
*
|
||||||
* @param fromIp 开始IP
|
* @param fromIp 开始IP,包含,点分十进制
|
||||||
* @param toIp 结束IP
|
* @param toIp 结束IP,包含,点分十进制
|
||||||
* @return IP数量
|
* @return IP数量
|
||||||
*/
|
*/
|
||||||
public static int countByIpRange(final String fromIp, final String toIp) {
|
public static int countByIpRange(final String fromIp, final String toIp) {
|
||||||
final long toIpLong = ipv4ToLong(toIp);
|
final long toIpLong = ipv4ToLong(toIp);
|
||||||
final long fromIpLong = ipv4ToLong(fromIp);
|
final long fromIpLong = ipv4ToLong(fromIp);
|
||||||
if (fromIpLong > toIpLong) {
|
return countByIpRange(fromIpLong, toIpLong);
|
||||||
throw new IllegalArgumentException("to IP must be greater than from IP!");
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* 获得 指定区间内的 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;
|
int count = 1;
|
||||||
final int[] fromIpSplit = StrUtil.split(fromIp, CharUtil.DOT).stream().mapToInt(Integer::parseInt).toArray();
|
count += (getPartOfIpLong(toIp, 4) - getPartOfIpLong(fromIp, 4));
|
||||||
final int[] toIpSplit = StrUtil.split(toIp, CharUtil.DOT).stream().mapToInt(Integer::parseInt).toArray();
|
count += (getPartOfIpLong(toIp, 3) - getPartOfIpLong(fromIp, 3)) << 8;
|
||||||
for (int i = fromIpSplit.length - 1; i >= 0; i--) {
|
count += (getPartOfIpLong(toIp, 2) - getPartOfIpLong(fromIp, 2)) << 16;
|
||||||
count += (toIpSplit[i] - fromIpSplit[i]) * Math.pow(256, fromIpSplit.length - i - 1);
|
count += (getPartOfIpLong(toIp, 1) - getPartOfIpLong(fromIp, 1)) << 24;
|
||||||
}
|
|
||||||
return count;
|
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:掩码位不合法
|
* @return true:掩码位合法;false:掩码位不合法
|
||||||
*/
|
*/
|
||||||
public static boolean isMaskBitValid(final int maskBit) {
|
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 {
|
|||||||
* </pre>
|
* </pre>
|
||||||
* 当然,还有127这个网段是环回地址
|
* 当然,还有127这个网段是环回地址
|
||||||
*
|
*
|
||||||
* @param ipAddress IP地址
|
* @param ipAddress IP地址,点分十进制
|
||||||
* @return 是否为内网IP
|
* @return 是否为内网IP
|
||||||
* @since 5.7.18
|
* @since 5.7.18
|
||||||
*/
|
*/
|
||||||
public static boolean isInnerIP(final String ipAddress) {
|
public static boolean isInnerIP(final String ipAddress) {
|
||||||
final boolean isInnerIp;
|
|
||||||
final long ipNum = ipv4ToLong(ipAddress);
|
final long ipNum = ipv4ToLong(ipAddress);
|
||||||
|
return isBetween(ipNum, A_INNER_IP_LONG_BEGIN, A_INNER_IP_LONG_END)
|
||||||
final long aBegin = ipv4ToLong("10.0.0.0");
|
|| isBetween(ipNum, B_INNER_IP_LONG_BEGIN, B_INNER_IP_LONG_END)
|
||||||
final long aEnd = ipv4ToLong("10.255.255.255");
|
|| isBetween(ipNum, C_INNER_IP_LONG_BEGIN, C_INNER_IP_LONG_END)
|
||||||
|
|| LOCAL_IP.equals(ipAddress);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------- Private method start
|
//-------------------------------------------------------------------------------- Private method start
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 ip/掩码位 计算IP段的终止IP(Long型)
|
* 将匹配到的Ipv4地址转为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个分组分别处理
|
|
||||||
*
|
*
|
||||||
* @param matcher 匹配到的Ipv4正则
|
* @param matcher 匹配到的Ipv4正则
|
||||||
* @return ipv4对应long
|
* @return ip的long值
|
||||||
*/
|
*/
|
||||||
private static long matchAddress(final Matcher matcher) {
|
private static long matchAddress(final Matcher matcher) {
|
||||||
long addr = 0;
|
int addr = 0;
|
||||||
|
// 每个点分十进制数字 转为 8位二进制
|
||||||
for (int i = 1; i <= 4; ++i) {
|
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;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指定IP的long是否在指定范围内
|
* 指定IP是否在指定范围内
|
||||||
*
|
*
|
||||||
* @param userIp 用户IP
|
* @param userIp 用户IP
|
||||||
* @param begin 开始IP
|
* @param begin 开始IP,包含
|
||||||
* @param end 结束IP
|
* @param end 结束IP,包含
|
||||||
* @return 是否在范围内
|
* @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);
|
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 }形式中每个部分的值
|
||||||
|
* <p>例如,ip为{@literal 0xC0A802FA},第1部分的值为:
|
||||||
|
* <ul>
|
||||||
|
* <li>第1部分的值为:@literal 0xC0},十进制值为:192</li>
|
||||||
|
* <li>第2部分的值为:@literal 0xA8},十进制值为:168</li>
|
||||||
|
* <li>第3部分的值为:@literal 0x02},十进制值为:2</li>
|
||||||
|
* <li>第4部分的值为:@literal 0xFA},十进制值为:250</li>
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @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
|
//-------------------------------------------------------------------------------- Private method end
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.hutool.core.net;
|
package cn.hutool.core.net;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.map.BiMap;
|
import cn.hutool.core.map.BiMap;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
@ -73,4 +74,15 @@ public class MaskBit {
|
|||||||
return MASK_BIT_MAP.getKey(mask);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@ import org.junit.Assert;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.function.ThrowingRunnable;
|
import org.junit.function.ThrowingRunnable;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class Ipv4UtilTest {
|
public class Ipv4UtilTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -28,10 +26,16 @@ public class Ipv4UtilTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void longToIpTest() {
|
public void longToIpTest() {
|
||||||
final String ip = "192.168.1.255";
|
testLongToIp("192.168.1.255");
|
||||||
final long ipLong = Ipv4Util.ipv4ToLong(ip);
|
testLongToIp("0.0.0.0");
|
||||||
final String ipv4 = Ipv4Util.longToIpv4(ipLong);
|
testLongToIp("0.0.0.255");
|
||||||
Assert.assertEquals(ip, ipv4);
|
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
|
@Test
|
||||||
@ -44,9 +48,24 @@ public class Ipv4UtilTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void listTest(){
|
public void listTest(){
|
||||||
final int maskBit = Ipv4Util.getMaskBitByMask("255.255.255.0");
|
final String ip = "192.168.100.2";
|
||||||
final List<String> list = Ipv4Util.list("192.168.100.2", maskBit, false);
|
testGenerateIpList(ip, 22, false);
|
||||||
Assert.assertEquals(254, list.size());
|
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");
|
testGenerateIpList("10.1.0.1", "10.2.1.2");
|
||||||
|
|
||||||
@ -90,8 +109,9 @@ public class Ipv4UtilTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isMaskBitValidTest() {
|
public void isMaskBitValidTest() {
|
||||||
final boolean maskBitValid = Ipv4Util.isMaskBitValid(32);
|
for (int i = 1; i < 32; i++) {
|
||||||
Assert.assertTrue("掩码位合法检验", maskBitValid);
|
Assert.assertTrue("掩码位非法:" + i, Ipv4Util.isMaskBitValid(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -119,4 +139,19 @@ public class Ipv4UtilTest {
|
|||||||
Ipv4Util.list(fromIp, toIp).size()
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user