目录
一、网段范围
二、思路说明
三、代码
1、将一个ip转为数字
2、转换子网掩码(255.255.255.0 转为 24)
3、根据 ip 与 掩码 计算最大值和最小值
4、测试
5、完整代码
四、难点讲解
1、转换子网掩码, 例:255.255.255.0 转为 24
2、根据 ip 与 掩码 的二进制 计算最大值和最小值
一、网段范围
大家在开发过程中可能会遇到对比网段的逻辑,让我们先来了解了解常见的网段范围写法
第一种 192.168.0.0-192.168.0.255
第二种 192.168.0.222 255.255.255.0
第三种 192.168.0.222/24
二、思路说明
如果一个ip可以用一个数字表示,那么就可以把一个网段范围用一个数字范围表示,这样就可以直接用大于小于等于来对比,听起来是不是很简单!
我们知道在判断时,将网段ip转为二进制 , 子网掩码也转为二进制, 然后将对比的ip也转为二进制,若(网段ip二进制每一位 并 子网掩码二进制 ) 等于 (对比的ip二进制每一位 并 子网掩码二进制),则该该ip 在网段范围中,反之则不在网段范围中。
所以,将一个ip用数字表示,可以先转为二进制,然后根据掩码算出最大最小的二进制值,然后就可以转回十进制进行对比了。
将网段ip 转为二进制(如下图,192.168.0.222 用数字 3232235742 代表)
前面说的第一种网段范围情况:直接用横杠分割,根据第一个得出最小值,根据第二个得出最大值
前面说的第二种网段范围情况:将子网掩码转成一个数字,第三种一样处理
前面说的第三种网段范围情况:最小值根据掩码将二进制可变位变为零,最大值根据掩码将二进制可变位变为零
三、代码
1、将一个ip转为数字
public static BigInteger getBigIntegerByip(String ip) {
BigInteger result = BigInteger.ZERO;
String[] addrSegments = ip.split("\\.");
for(int i = 0; i < 4; i++){
//ip以 "点" 分成4个数, 第一个数左移24位, 第二个数左移16位, 第三个数左移8位,第四个不移,将它们相加
BigInteger bigInteger = BigInteger.valueOf(Long.parseLong(addrSegments[i]))
.shiftLeft(8 * (3 - i));
result = result.add(bigInteger);
}
return result;
}
2、转换子网掩码(255.255.255.0 转为 24)
private static IpRangeData getIpRangeDataByMask(String ipSubnetMask) {
String[] split = ipSubnetMask.split(" ");
String binaryMask = subnetMaskToBinary(split[1]);
int zero = binaryMask.indexOf("0");
int one = binaryMask.lastIndexOf("1");
if(zero != -1 && one != -1 && zero < one) {
//反掩码情况
return null;
}
return getIpRangeDataByMask(split[0], zero == -1 ? 32 : zero);
}
3、根据 ip 与 掩码 计算最大值和最小值
private static IpRangeData getIpRangeDataByMask(String ip, int mask) {
int varBin = 32 - mask;
BigInteger bigIntegerByip = getBigIntegerByip(ip);
BigInteger min = bigIntegerByip.shiftRight(varBin).shiftLeft(varBin);
BigInteger varFulll = BigInteger.ONE.shiftLeft(varBin).subtract(BigInteger.ONE);
BigInteger max = min.add(varFulll);
IpRangeData result = new IpRangeData();
result.setStart(min);
result.setEnd(max);
return result;
}
4、测试
5、完整代码
import java.math.BigInteger;
/**
* ip工具类
*
* @author zenglingyao
* @date 2023/07/03
*/
public class IpUtil {
public static BigInteger getBigIntegerByip(String ip) {
BigInteger result = BigInteger.ZERO;
String[] addrSegments = ip.split("\\.");
for(int i = 0; i < 4; i++){
//ip以 "点" 分成4个数, 第一个数左移24位, 第二个数左移16位, 第三个数左移8位,第四个不移,将它们相加
BigInteger bigInteger = BigInteger.valueOf(Long.parseLong(addrSegments[i]))
.shiftLeft(8 * (3 - i));
result = result.add(bigInteger);
}
return result;
}
/**
* 解析网段
*
* @param segment 段
* @return {@link IpRangeData}
*/
public static IpRangeData parseSegment(String segment) {
String trim = segment.trim();
if (trim.contains("-")) {
return getIpRangeDataByRange(trim);
}else if (trim.contains("/")) {
String[] split = trim.split("/");
return getIpRangeDataByMask(split[0], Integer.parseInt(split[1]));
}else {
return getIpRangeDataByMask(segment);
}
}
private static IpRangeData getIpRangeDataByRange(String ipRange) {
String[] split = ipRange.split("-");
String startIp = split[0];
String endIp = split[1];
IpRangeData result = new IpRangeData();
result.setStart(getBigIntegerByip(startIp));
result.setEnd(getBigIntegerByip(endIp));
return result;
}
private static IpRangeData getIpRangeDataByMask(String ipSubnetMask) {
String[] split = ipSubnetMask.split(" ");
String binaryMask = subnetMaskToBinary(split[1]);
int zero = binaryMask.indexOf("0");
int one = binaryMask.lastIndexOf("1");
if(zero != -1 && one != -1 && zero < one) {
//反掩码情况
return null;
}
return getIpRangeDataByMask(split[0], zero == -1 ? 32 : zero);
}
private static String subnetMaskToBinary(String subnetMask) {
String[] split = subnetMask.split("\\.");
StringBuilder result = new StringBuilder();
for (String subnetMaskArr : split) {
int decimal = Integer.parseInt(subnetMaskArr);
StringBuilder target = new StringBuilder();
for (int i = 0; i < 8; i++) {
target.insert(0, decimal % 2);
decimal /= 2;
}
result.append(target);
}
return result.toString();
}
private static IpRangeData getIpRangeDataByMask(String ip, int mask) {
int varBin = 32 - mask;
BigInteger bigIntegerByip = getBigIntegerByip(ip);
BigInteger min = bigIntegerByip.shiftRight(varBin).shiftLeft(varBin);
BigInteger varFulll = BigInteger.ONE.shiftLeft(varBin).subtract(BigInteger.ONE);
BigInteger max = min.add(varFulll);
IpRangeData result = new IpRangeData();
result.setStart(min);
result.setEnd(max);
return result;
}
public static void main(String[] args) {
//32位掩码情况
String ipMask1 = "192.168.0.1/32";
String ipSubnetMask1 = "192.168.0.1 255.255.255.255";
String ipRange1 = "192.168.0.1-192.168.0.1";
//0位掩码情况
String ipMask2 = "192.168.0.1/0";
String ipSubnetMask2 = "192.168.0.1 0.0.0.0";
String ipRange2 = "0.0.0.0-255.255.255.255";
//正常掩码情况1
String ipMask3 = "192.168.0.1/24";
String ipSubnetMask3 = "192.168.0.1 255.255.255.0";
String ipRange3 = "192.168.0.0-192.168.0.255";
//正常掩码情况2
String ipMask4 = "192.168.0.1/26";
String ipSubnetMask4 = "192.168.0.1 255.255.255.192";
String ipRange4 = "192.168.0.192-192.168.0.63";
//反掩码情况
String ipSubnetMask5 = "192.168.0.1 255.255.255.247";
System.out.println("\r\n--------32位掩码情况--------");
System.out.println(parseSegment(ipMask1));
System.out.println(parseSegment(ipSubnetMask1));
System.out.println(parseSegment(ipRange1));
System.out.println("\r\n---------0位掩码情况--------");
System.out.println(parseSegment(ipMask2));
System.out.println(parseSegment(ipSubnetMask2));
System.out.println(parseSegment(ipRange2));
System.out.println("\r\n--------正常掩码情况1--------");
System.out.println(parseSegment(ipMask3));
System.out.println(parseSegment(ipSubnetMask3));
System.out.println(parseSegment(ipRange3));
System.out.println("\r\n--------正常掩码情况2--------");
System.out.println(parseSegment(ipMask4));
System.out.println(parseSegment(ipSubnetMask4));
System.out.println(parseSegment(ipRange4));
System.out.println("\r\n---------反掩码情况---------");
System.out.println(parseSegment(ipSubnetMask5));
}
}
class IpRangeData {
BigInteger start;
BigInteger end;
public BigInteger getStart() {
return start;
}
public void setStart(BigInteger start) {
this.start = start;
}
public BigInteger getEnd() {
return end;
}
public void setEnd(BigInteger end) {
this.end = end;
}
@Override
public String toString() {
return "开始值为:" + start + ", 结束值为" + end;
}
}
四、难点讲解
1、转换子网掩码, 例:255.255.255.0 转为 24
①将 255.255.255.0 先转为 1111 1111 1111 1111 1111 1111 0000 0000
②判断第一个0与最后一个1的位置关系是否正确(判断是否反掩码),第一个0下标为结果
2、根据 ip 与 掩码 的二进制 计算最大值和最小值
①最小值
可变位全为0时最小,比如最后5位是可变位,先右移5位(最右面的5位无论是0还是1都没了),再左移5位(最右面加回来五个0)
②最大值
可变位全为1时最大,比如最后5位是可变位,前面得到的最小值加5个1就行了,如何得到5个1对应的数,把1左移5位 得到 100000 ,这个数减1 得 11111