🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,
15年
工作经验,精通Java编程
,高并发设计
,Springboot和微服务
,熟悉Linux
,ESXI虚拟化
以及云原生Docker和K8s
,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea
IP段转CIDR:Java实现
首先,需要确认CIDR是什么?CIDR表示的是无类别域间路由,通常形式是IP地址后跟一个斜杠和数字,比如192.168.1.0/24。这个数字表示网络前缀的位数,剩下的位数用于主机地址。CIDR的作用是更高效地分配IP地址,减少浪费。
我们现在要实现,将给定的起始IP和结束IP转换为CIDR块。那么,如何从两个IP地址中找到覆盖它们的CIDR呢?可能需要分解成多个CIDR块,因为单个CIDR可能无法覆盖整个范围,尤其是当范围不是连续的2的幂次方时。
一、需要考虑以下几点
-
将IP地址转换为整数:IPv4地址是32位的,可以将每个部分转换为二进制,然后组合成一个长整数,这样便于计算。例如,192.168.1.0转换为整数是3232235776。
-
确定起始和结束IP的整数形式:需要将输入的字符串拆分四个部分,每个部分转换为整数,并进行位移组合成一个长整型。
-
计算CIDR块:从起始地址开始,找到最大的前缀长度(即最小的子网),使得该子网包含在起始和结束范围内。然后,将起始地址递增到下一个子网的起始地址,重复这个过程直到覆盖整个范围。
这里的关键步骤是如何找到每个可能的CIDR块。例如,假设起始IP是192.168.0.0
,结束IP是192.168.3.255
。这个范围可以被分解为192.168.0.0/23
或者192.168.0.0/24
和192.168.1.0/24
以及192.168.2.0/23
等,但需要找到最合适的分解方式。
二、可能的算法步骤
- 将起始IP和结束IP转换为长整数。
- 如果起始IP大于结束IP,则交换它们。
- 初始化一个列表来保存CIDR块。
- 循环处理,直到起始IP超过结束IP:
- 计算起始IP的最低位有效位(即最大的后缀0的位数),这决定了当前可能的最大CIDR块。
- 同时,确定当前块的大小,不超过结束IP。
- 确定实际可以使用的掩码位数,使得该子网不超过结束IP。
- 将CIDR块添加到列表。
- 将起始IP加上当前块的大小,继续处理。
这里需要注意的是,每次找到的CIDR块应该是最大的可能块,以减少块的数量。例如,如果起始IP是192.168.0.0
,结束IP是192.168.0.255
,那么CIDR
是/24
。但如果结束IP是192.168.1.127
,可能需要分解为多个块,如/24和/25等。
在Java中实现时,需要处理大整数,因为IPv4是32位,可以使用long类型来避免符号问题。同时,掩码的计算可能需要位运算,比如找出最长的公共前缀。
另外,还需要处理一些特殊情况,比如起始和结束IP相同,这时候CIDR
就是/32
。或者起始IP到结束IP是一个连续的块,但无法被一个CIDR
覆盖,需要拆分成多个。
例如,起始IP是192.168.0.5
,结束IP是192.168.0.7
。这时候CIDR列表应该是192.168.0.5/32
, 192.168.0.6/31
,或者类似的组合。但需要确保每个CIDR块覆盖的IP范围在起始和结束之间。
三、Java程序实现步骤
现在,需要将这些逻辑转化为Java代码,需要以下步骤:
-
编写一个方法将IP字符串转换为长整数。
-
编写一个方法将长整数转换回IP字符串。
-
编写方法计算两个IP之间的CIDR块列表。
在转换IP到长整数时,需要将每个部分左移相应的位数,例如第一个部分左移24位,第二个左移16位,依此类推。同时,确保每个部分的数值在0-255
之间。
在计算CIDR块时,需要找到最大的掩码位数,使得该子网的起始地址加上块大小不超过结束IP。块大小是2^(32 - mask)
,所以需要找到最大的mask,使得start + size <= end + 1
。或者,另一种方式是找到起始IP的最低位有效位,然后逐步调整掩码位数。
3.1 如何计算mask?
可以计算从start到end的差值为diff = end - start +1
。然后,最大的块是最大的2的幂次方,不大于diff,并且块的大小还要考虑start的低位是否为0。
或者,找到从start开始的最低位有效位,例如,计算start的二进制中最低位的1的位置,然后块的大小是2^该位置,但是不能超过end - start +1。
例如,start的二进制是x,那么最大的块大小是最大的2的幂次方,使得块大小 <= diff
,并且块大小是start的二进制中最低位1所代表的值。
例如,假设start是192.168.0.5
(转换为整数是3232235525),二进制是…00000101。最低位的1的位置是0(因为最后一位是1),所以块大小是1,即mask是32。这样该块只包含start自己。但如果diff大于1,那么可能之后的下一个块可以更大。
或者,这可能不是最优的方式。正确的做法应该是找到最大的mask,使得该子网覆盖的起始地址是start,并且子网的结束地址不超过end。
这可能需要计算该子网的网络地址,然后找到最大的mask,使得该子网的广播地址不超过end。
例如,子网的网络地址是start & mask,而广播地址是network | (~mask & 0xFFFFFFFFL)。所以需要确保广播地址 <= end。
但这个过程可能比较复杂。因此,可能需要另一种方法:
对于当前的start,尝试找到最大的mask,使得该mask对应的块大小(即2^(32 - mask))使得start + block_size -1 <= end
.
同时,mask必须满足start的二进制中,后(32 - mask)位必须全为0,否则该子网的起始地址不是start,而是更小的地址。
例如,如果start是192.168.0.5
,而mask是24,那么子网的起始地址是192.168.0.0,而start不在该子网的起始地址,因此无法使用mask为24。因此,必须找到最大的mask,使得start是该子网的起始地址,即start的后(32 - mask)位必须是0。
因此,正确的步骤应该是:
计算从start开始,最大的后缀0的位数。这可以通过计算start的最低位1的位置,比如start的二进制中有n个后缀0,那么最大的mask是32 - n。此时,块大小是2^n。例如,start是192.168.0.0
(即…00000000),那么n是8,mask是24,块大小是256。
但如果start是192.168.0.128,二进制是…10000000,那么后缀0的位数是7,所以mask是25,块大小是128。此时,子网是192.168.0.128/25,广播地址是192.168.0.255。
但是,如果end是192.168.0.255,那么这个块可以包含。但是如果end是更小的值,比如192.168.0.200,那么需要调整mask,使得块大小不超过end - start +1。
因此,mask的确定应该是:
mask = 32 - Math.min(lowBit, log2(remainingSize))
其中,lowBit是start的最低位1的位置,remainingSize是end - start +1。
或者,另一种方法是:
mask = 32 - Math.min(lowBit, 32 - (int)(Math.log(remainingSize)/Math.log(2)))
但是,计算lowBit的方式需要正确。例如,对于start的二进制,找到最右边1的位置。比如,start的二进制是…0001000,那么lowBit是3(从0开始计数),即2^3=8。所以块的大小是8,mask是32 -3 =29。
3.2 如何计算lowBit呢?
可以用位运算来找最右边的1的位置。例如,对于long类型的start,取值为start & -start,这会得到一个只有最右边1的数,然后计算log2。
例如,start & -start可以得到一个数,其中只有最右边的1被保留。例如,start是5(二进制101),start & -start的结果是1(二进制1),所以log2(1)=0,即lowBit=0。此时,块的大小是1,mask=32-0=32
.
如果是start是8(二进制1000),则start & -start=8
,log2(8)=3
,所以lowBit=3
,块的大小是8,mask=29
.
所以,lowBit = log2(start & -start)
. 但如何计算log2?可以用位运算,或者循环右移。
在Java中,可以使用Long.numberOfTrailingZeros()
方法,这个方法返回的是二进制中最低位1后面的0的个数。例如,对于8(1000),numberOfTrailingZeros
是3。此时,lowBit就是这个值,即块的大小是1 << lowBit。
但这个方法是否适用于所有情况?
假设start是0,那么start & -start是0,这可能有问题。但start在这里是介于起始和结束之间的,所以可能不会为0?
但起始IP可能为0,例如0.0.0.0到0.0.0.255。此时,lowBit是8,块的大小是256,mask是24.
所以,lowBit的计算应该是:
long diff = start & -start;
如果diff ==0
,那么lowBit=32
?或者如何处理?
或者,另一种方式,使用Long.numberOfTrailingZeros(startIpLong)
来获取最低位1后面的0的个数。例如,对于startIpLong=8(二进制1000),这个方法会返回3,因为末尾有3个0。此时,块的大小是1 << 3 =8.
所以,lowBit = Long.numberOfTrailingZeros(startIpLong | 0xFFFFFFFF00000000L)
? 不太确定,可能需要仔细测试。
或者,对于IPv4的32位,startIpLong是32位的数值,存储在long类型的高32位或者低32位?可能要看转换方式是否正确。例如,前面的转换函数是否正确地将IP转换为长整数,比如将第一个八位移到高位。
例如,IP地址a.b.c.d转换为长整数的方式是:a<<24 | b<<16 | c<<8 | d。这样,IPv4的32位被放在long的高32位还是低32位?
假设转换正确的话,那么对于192.168.0.5,转换为长整数是 (192 <<24) | (168<<16) | (0<<8) |5 = 3232235525。二进制表示为:
11000000 10101000 00000000 00000101
这里,最低位的1是在第0位(最后一个字节的5是00000101,最低位是1)。所以,Long.numberOfTrailingZeros(3232235525)
应该是0,因为最低位是1,后面没有0。所以块的大小是1,mask是32-0=32。
这样,每个块的大小是根据start的最低位1的位置决定的,但也要确保块的大小不超过剩余的地址空间(即end - start +1)。
3.3 综合起来,步骤如下
-
将
startIp
和endIp
转换为长整数s和e,确保s <=e。 -
初始化结果列表。
-
当
s <= e
时,循环:
a. 计算当前s的最低位1的位置,得到lowBit = Long.numberOfTrailingZeros(s)
.
b. 可能的块大小maxSize = 1 << lowBit
.
c. 但maxSize不能超过e - s +1
,所以实际块大小是Math.min(maxSize, e -s +1)
.
d. 这时候,需要找到最大的mask
,使得块大小为actualSize
。因为actualSize
必须是2的幂,所以mask = 32 - log2(actualSize)
.
e. 所以,mask = 32 - (int)(Math.log(actualSize)/Math.log(2))
.
f. 将CIDR
块添加到结果列表:IP/mask
.
g. s += actualSize
.
这样,每次循环处理一个块,直到覆盖整个范围。
例如,start=192.168.0.5
,end=192.168.0.7
:
s=3232235525 (0xC0A80005), e=3232235527
.
第一次循环:
lowBit = trailing zeros of s=5
(二进制101),即0位,所以maxSize=1<<0=1
.
actualSize=min(1, 7-5+1=3) →1
.
mask=32 -0=32
.
CIDR块是192.168.0.5/32
.
s +=1 →6
.
第二次循环:
s=6
,二进制00000110,trailing zeros是1(因为最后两位是 10 →最低位是0?)
不,Long.numberOfTrailingZeros(6)
是1,因为6的二进制是110,末尾有一个0。
所以,lowBit=1 →maxSize=2
.
actualSize=min(2, 7-6+1=2) →2
.
mask=32 -1=31
.
CIDR
块是192.168.0.6/31
,覆盖6和7.
s +=2 →8,超出e=7,循环结束。
所以,结果是两个CIDR块:/32和/31.
这似乎正确。
另一个例子,start=192.168.0.0
,end=192.168.3.255
:
s=3232235520
, e=3232238079
.
第一次循环:
lowBit=Long.numberOfTrailingZeros(s) →s=0xC0A80000
→二进制是11000000 10101000 00000000 00000000
→末尾有16个零?或者可能要看具体的转换方式。
如果IP地址转换为长整数的方式是每个八位作为高位,例如:
对于192.168.0.0,转换为:
192 <<24 | 168 <<16 | 0 <<8 |0 →即3232235520
,二进制是11000000 10101000 00000000 00000000
。
Long.numberOfTrailingZeros(3232235520)
→计算末尾的0的个数。3232235520
的二进制是:
11000000 10101000 00000000 00000000
→最后的16位都是0,所以 trailing zeros
是16.
所以,lowBit=16 →maxSize=1<<16=65536
.
但实际剩余的大小是 e -s +1 = 3232238079 -3232235520 +1=2560
.
所以actualSize=min(65536, 2560)=2560
.
但2560不是2的幂次方。这时候需要调整,找到最大的2的幂次方,不超过2560
.
所以,这里可能我的之前的思路有问题,即块的大小必须是2的幂次方,而实际剩余的大小可能不是,因此需要取最大可能的块,其大小是2的幂次方,并且不超过剩余的大小。
这时候,应该怎么做?
例如,在步骤c中,maxSize由lowBit决定,即可能的块大小是2^lowBit,但可能这个大小超过了剩余的大小,因此需要将actualSize设置为最大的2的幂次方,不超过剩余的大小。
或者,另一种方式,actualSize是最大的2的幂次方,使得actualSize <= remainingSize,并且actualSize <= maxSize(即由lowBit决定的块大小)。
例如,remainingSize
是2560,那么最大的2的幂次方是2048(2^11=2048),而maxSize由lowBit=16是65536,所以actualSize=2048.
此时,mask=32 -11=21.
这样,CIDR块是192.168.0.0/21?但是这样的话,该块的范围是192.168.0.0到192.168.7.255,但用户的结束IP是192.168.3.255,因此这样会超出范围。这说明我的逻辑有问题。
哦,这说明原来的算法可能存在问题。可能需要重新考虑如何确定块的大小。
正确的逻辑应该是,找到最大的mask,使得该子网的起始地址是s,并且该子网的结束地址 <=e.
也就是说,子网的掩码决定了块的大小是2^(32 - mask),所以我们需要找到最大的mask(即最小的块大小),使得 s + (2^(32 - mask)) -1 <=e.
同时,该mask必须满足s的后(32 - mask)位是0,也就是s是该子网的起始地址。
例如,对于s=192.168.0.0
,e=192.168.3.255
.
最大的mask是22,因为块大小是2(32-22)=210=1024,而s+1024-1=192.168.3.255
。这正是需要的。
所以,正确的CIDR
是192.168.0.0/22
.
因此,在这种情况下,算法应该返回一个CIDR块,而不是多个。那问题出在哪里?
块的大小应该同时满足:
-
该块的大小是2的幂次方,并且该块的起始地址是s。
-
该块的结束地址不超过e.
所以,块的大小应该是最大的可能的2的幂次方,满足 s + size -1 <=e,并且 size是最大的可能值,并且s mod size ==0.
3.4 如何计算这样的size?
算法步骤:
-
计算remaining = e - s +1.
-
初始size为最大的可能,即最大的2的幂次方 <= remaining.
-
同时,size必须满足 s & (size -1) ==0 (即s是该size的倍数)。
如果这两个条件满足,则size可以是该值,否则,需要将size减半,直到满足条件。
例如,对于s=192.168.0.0,e=192.168.3.255,remaining=1024.
最大的size是1024,且s mod 1024 ==0,所以可以使用size=1024,mask=22.
所以,正确的CIDR是/22.
那如何将此逻辑转化为代码?
实现步骤:
-
计算remaining = e -s +1.
-
计算
maxMask = 32 - (int)(Math.log(remaining)/Math.log(2))
→但这可能不正确,因为remaining可能不是2的幂次方。
或者,找到最大的mask,使得 2^(32 - mask) <= remaining,并且 s & (2^(32 -mask) -1) ==0.
正确的算法应该是:
循环处理,每次找到最大的size(2的幂次方),使得:
size <= remaining
并且 s + size -1 <=e
并且 s & (size -1) ==0 (即s是size的整数倍)
然后,mask=32 - log2(size).
然后,将CIDR块加入列表,s += size,remaining = e -s +1.
重复直到remaining=0.
现在,如何在代码中实现这一点?
步骤:
while s <=e:
remaining = e -s +1;
maxSize = 1 << 30; // 初始为较大的数,比如2^30
size = 0;
for (int shift = 0; shift <=32; shift++) {
currentSize = 1 << shift;
if (currentSize > remaining) break;
if ((s & (currentSize -1)) ==0) {
size = currentSize;
}
}
// 此时size是最大的满足条件的size
mask = 32 - log2(size) →即mask=32 - shift.
add cidr: ipToString(s) + "/" + mask
s += size
但这样可能需要一个循环来找到最大的size。
或者,可以使用位运算来找到最大的可能size:
size = remaining;
然后,找到最大的size,是2的幂次方,且满足 size <= remaining,并且 (s & (size -1)) ==0.
例如:
size = Integer.highestOneBit(remaining); // 最大的2的幂次方 <= remaining
while (size >0) {
if ((s & (size -1)) ==0) {
break;
}
size >>=1;
}
这样,size被调整为最大的满足条件的size.
例如,计算size的方法:
long size = Long.highestOneBit(remaining);
然后,循环检查 (s & (size -1)) ==0,否则将size减半,直到找到满足条件的size.
代码可能如下:
long remaining = e - s +1;
long size = Long.highestOneBit(remaining);
while (size >0) {
if ((s & (size -1)) ==0) {
break;
}
size >>=1;
}
if (size ==0) {
size =1;
}
然后,mask=32 - log2(size)
. 但如何计算log2(size)
?
可以用Long.numberOfLeadingZeros
来得到。例如,对于size=1024
,二进制是10000000000
,共11位,所以numberOfLeadingZeros
是64-11=53
。但Long.numberOfLeadingZeros(1024)
返回的是64 - 11 =53
?这可能需要调整。
或者,计算log2(size)可以使用位运算:
int logSize = 63 - Long.numberOfLeadingZeros(size);
例如,size=1024 →63 - 53(numberOfLeadingZeros(1024))
是10 →log2(1024)=10
.
所以,mask=32 - logSize
.
这样,例如size=1024 →mask=22
.
所以,综合以上分析,Java代码的大致结构可以是:
public static List<String> ipRangeToCidrs(String startIp, String endIp) {
// 转换startIp和endIp为long s和e
List<String> cidrs = new ArrayList<>();
long s = ipToLong(startIp);
long e = ipToLong(endIp);
while (s <= e) {
// 计算remaining
long remaining = e - s +1;
// 计算最大的size
long size = 1;
int shift =0;
// 找到最大的size=2^shift <= remaining,并且s & (size-1) ==0
for (shift =0; (1L << (shift+1)) <= remaining; shift++) {
if ((s & ( (1L << (shift+1)) -1 )) !=0) {
break;
}
}
size = 1L << shift;
// 计算mask
int mask = 32 - shift;
// 添加CIDR
cidrs.add(longToIp(s) + "/" + mask);
// 更新s
s += size;
}
return cidrs;
}
四、ipToLong
函数:
public static long ipToLong(String ip) {
String[] octets = ip.split("\\.");
if (octets.length !=4) {
throw new IllegalArgumentException("Invalid IP address");
}
long result =0;
for (int i=0; i<4; i++) {
int octet = Integer.parseInt(octets[i]);
if (octet <0 || octet >255) {
throw new IllegalArgumentException("Invalid IP octet");
}
result <<=8;
result |= octet;
}
return result;
}
这样,对于192.168.0.5
,结果是 (192 <<24) | (168 <<16) | (0 <<8) |5 = 3232235525L
.
五、longToIp
函数:
public static String longToIp(long ip) {
return String.format("%d.%d.%d.%d",
(ip >>24) & 0xFF,
(ip >>16) & 0xFF,
(ip >>8) & 0xFF,
ip & 0xFF);
}
这样,3232235525L
会被正确转换为192.168.0.5
.
六、编写主要的循环部分
public static List<String> ipRangeToCidr(String startIp, String endIp) {
long start = ipToLong(startIp);
long end = ipToLong(endIp);
List<String> result = new ArrayList<>();
if (start > end) {
throw new IllegalArgumentException("Start IP must be <= End IP");
}
while (start <= end) {
// 计算当前start的最低位1的位置,确定最大的可能的mask
long maxSize = 1;
int shift =0;
// 找到最大的shift,使得 (1 << shift) <= remaining,并且 (start & ((1 << shift) -1)) ==0
long remaining = end - start +1;
// 初始shift为0,逐步增加,直到无法满足条件
for (shift =0; (1L << (shift+1)) <= remaining; shift++) {
// 检查如果增加shift后,是否start的后面的位都是0
long mask = (1L << (shift +1)) -1;
if ((start & mask) !=0) {
break;
}
}
long currentSize = 1L << shift;
int mask = 32 - shift;
result.add(longToIp(start) + "/" + mask);
start += currentSize;
}
return result;
}
综上所述,最终的Java函数应该包括:
-
ipToLong
和longToIp
的转换函数。 -
主函数处理循环,找到每个可能的
CIDR
块。 -
正确计算size和mask.
七、完整代码实现
以下是完整的Java 代码,并处理可能的异常和边界情况,可以将起始 IP 和结束 IP 转换为最精确的 CIDR 块列表。该方法通过位运算动态计算每个 CIDR 块的范围,确保覆盖所有 IP 且不重叠:
import java.util.ArrayList;
import java.util.List;
public class CidrCalculator {
public static List<String> convertIpRangeToCidr(String startIp, String endIp) {
long start = ipToLong(startIp);
long end = ipToLong(endIp);
List<String> cidrList = new ArrayList<>();
if (start > end) {
throw new IllegalArgumentException("起始IP不能大于结束IP");
}
while (start <= end) {
// 计算当前起始IP的最低位有效位(决定CIDR块的大小)
int suffixZeros = Long.numberOfTrailingZeros(start);
long maxSize = 1L << suffixZeros; // 可能的块大小(2^suffixZeros)
long remaining = end - start + 1; // 剩余需要覆盖的IP数量
// 实际块大小不能超过剩余范围
long actualSize = Math.min(maxSize, remaining);
// 计算CIDR的掩码位数(32 - log2(actualSize))
int mask = 32 - (int) (Math.log(actualSize) / Math.log(2));
// 将CIDR块加入列表
cidrList.add(longToIp(start) + "/" + mask);
// 移动到下一个块的起始IP
start += actualSize;
}
return cidrList;
}
// 将IP字符串转换为32位整数(用long存储)
private static long ipToLong(String ip) {
String[] octets = ip.split("\\.");
if (octets.length != 4) {
throw new IllegalArgumentException("无效的IP地址格式");
}
long result = 0;
for (int i = 0; i < 4; i++) {
int octet = Integer.parseInt(octets[i]);
if (octet < 0 || octet > 255) {
throw new IllegalArgumentException("IP八位组超出范围");
}
result = (result << 8) | octet;
}
return result;
}
// 将32位整数转换为IP字符串
private static String longToIp(long ip) {
return ((ip >> 24) & 0xFF) + "." +
((ip >> 16) & 0xFF) + "." +
((ip >> 8) & 0xFF) + "." +
(ip & 0xFF);
}
// 测试用例
public static void main(String[] args) {
// 示例1:单个IP(/32)
test("192.168.0.5", "192.168.0.5"); // ["192.168.0.5/32"]
// 示例2:连续两个IP(/31)
test("192.168.0.6", "192.168.0.7"); // ["192.168.0.6/31"]
// 示例3:一个完整的C类子网(/24)
test("192.168.0.0", "192.168.0.255"); // ["192.168.0.0/24"]
// 示例4:跨子网的IP范围
test("192.168.0.5", "192.168.0.7"); // ["192.168.0.5/32", "192.168.0.6/31"]
}
private static void test(String startIp, String endIp) {
List<String> cidrs = convertIpRangeToCidr(startIp, endIp);
System.out.println("IP范围: " + startIp + " - " + endIp);
System.out.println("CIDR块: " + String.join(", ", cidrs) + "\n");
}
}
7.1 代码说明
-
核心逻辑
- 位运算计算:通过
Long.numberOfTrailingZeros
找到起始 IP 的最低位有效位,确定最大可能的 CIDR 块大小。 - 动态调整块大小:根据剩余 IP 范围 (
remaining
) 和起始 IP 的对齐要求,动态调整实际 CIDR 块大小。
- 位运算计算:通过
-
关键方法
ipToLong()
:将 IP 字符串转换为 32 位整数(用long
存储,避免符号问题)。longToIp()
:将整数转换回点分十进制格式。convertIpRangeToCidr()
:主方法,遍历 IP 范围生成 CIDR 列表。
-
测试案例
- 覆盖单 IP、连续 IP、完整子网和跨子网范围,验证不同场景的准确性。
7.2 执行示例
输入:
convertIpRangeToCidr("192.168.0.6", "192.168.0.7");
输出:
CIDR块: 192.168.0.6/31
输入:
convertIpRangeToCidr("192.168.0.5", "192.168.0.7");
输出:
CIDR块: 192.168.0.5/32, 192.168.0.6/31