调试Groovy CIDR子网可用IP生成代码:返回空列表问题
调试CIDR子网可用IP生成代码
你的代码返回空列表的核心问题在于子网掩码的计算逻辑错误,以及后续广播地址计算时的有符号整数溢出问题,导致循环条件不成立,没有生成任何IP。
问题分析
子网掩码整数计算错误
原代码中subnetMaskInt = (1 << (32 - subnetMask.toInteger())) - 1的逻辑完全颠倒:这个计算得到的是主机位全1的数值,而非子网掩码(子网掩码要求网络位全1、主机位全0)。比如对于/27,32-27=5,计算结果是31(二进制00011111),但正确的子网掩码应该是0xFFFFFFE0(二进制11111111 11111111 11111111 11100000)。广播地址计算的有符号整数问题
由于子网掩码计算错误,~subnetMaskInt在Groovy的有符号整数环境下会生成负数,导致broadcastAddress为负数,lastUsableIp = broadcastAddress -1也变成负数,而firstUsableIp是正数,循环条件i <= lastUsableIp永远不成立,因此没有IP被添加到列表中。
修正后的代码
static List<String> generateAvailableIps(String subnetCidr) { // Parse the CIDR notation def (ipAddress, subnetMaskStr) = subnetCidr.split("/") int mask = subnetMaskStr.toInteger() // Convert IP address to 32-bit integer def ipInt = ipAddress.split("\\.").inject(0) { acc, value -> (acc << 8) + value.toInteger() } // Calculate correct subnet mask (network bits set to 1) def subnetMaskInt = (-1) << (32 - mask) // Ensure we're dealing with unsigned 32-bit value subnetMaskInt &= 0xFFFFFFFF // Get network address def networkAddress = ipInt & subnetMaskInt // Calculate host bits range for broadcast address def hostBits = (1 << (32 - mask)) - 1 def broadcastAddress = networkAddress | hostBits // Determine usable IP range (exclude network and broadcast) def firstUsableIp = networkAddress + 1 def lastUsableIp = broadcastAddress - 1 def availableIps = [] // Handle edge cases like /31 (no usable IPs) or /32 (single IP, no usable) if (firstUsableIp <= lastUsableIp) { for (long i = firstUsableIp; i <= lastUsableIp; i++) { def octet1 = (i >> 24) & 0xff def octet2 = (i >> 16) & 0xff def octet3 = (i >> 8) & 0xff def octet4 = i & 0xff availableIps.add("$octet1.$octet2.$octet3.$octet4") } } return availableIps } // Example usage def availableIps = generateAvailableIps("192.168.35.32/27") println(availableIps)
关键修改说明
- 修正子网掩码计算:使用
(-1) << (32 - mask)生成网络位全1的子网掩码,再通过& 0xFFFFFFFF确保数值为无符号32位整数,避免负数问题。 - 广播地址计算优化:直接通过
networkAddress | hostBits生成广播地址(hostBits是主机位全1的数值),逻辑更清晰且避免有符号整数问题。 - 添加边界判断:当
firstUsableIp > lastUsableIp时(比如/31、/32子网),跳过循环,避免无效执行。 - 循环变量改为long:防止IP整数超过int的范围(IPv4最大数值为2^32-1,刚好触及int的边界,用long更安全)。
运行修正后的代码,192.168.35.32/27子网会返回正确的可用IP列表:[192.168.35.33, 192.168.35.34, ..., 192.168.35.62](共30个可用IP)。
内容的提问来源于stack exchange,提问作者Prashant Shete
相关产品推荐
相关产品推荐

