如何使用Dart计算CIDR格式IP段的起始与结束IP地址
CIDR格式IPv4转起止IP区间(Dart实现)
核心计算逻辑
- 拆分输入:将CIDR字符串按
/分割,得到点分十进制IP段和前缀长度n,n的合法取值范围为0~32,超出范围直接判定为非法输入。 - IP转32位整数:把点分四段的IPv4每段转成0~255的整数,从左到右按
第一段 << 24 | 第二段 << 16 | 第三段 << 8 | 第四段的规则,拼成一个32位整数,方便做位运算。 - 计算子网掩码:前缀长度n代表前n位是网络位,掩码值为
(0xFFFFFFFF << (32 - n)) & 0xFFFFFFFF,末尾做与运算避免Dart整数移位时出现符号位异常。 - 计算网络地址:将IP对应的32位整数和子网掩码做按位与运算,得到当前IP所在子网的网络地址(主机位全0)。
- 计算主机位掩码:主机位长度为
32-n,主机位全1的掩码值为(1 << (32 - n)) - 1。 - 计算广播地址:网络地址和主机位掩码做按位或运算,得到子网的广播地址(主机位全1)。
- 取可用IP区间:常规场景下网络地址(主机位全0)和广播地址(主机位全1)不分配给主机使用,因此实际起止IP为
网络地址 + 1到广播地址 - 1;前缀长度为32时,32-n=0,网络地址和广播地址都是输入IP本身,区间就是单个IP。
注:你问题描述中
198.162.1.1/24对应的结束IP写为124是笔误,按照计算逻辑/24前缀的可用IP区间是198.162.1.1 - 198.162.1.254,和你给出的192.168.0.1/25输出192.168.0.1 - 192.168.0.126的逻辑完全匹配。
Dart实现代码
/// 将CIDR格式IPv4地址转换为 起始IP - 结束IP 格式的字符串 /// 输入示例:192.168.0.1/25 /// 输出示例:192.168.0.1 - 192.168.0.126 String cidrToIpRange(String cidr) { // 拆分CIDR字符串 final parts = cidr.split('/'); if (parts.length != 2) { throw ArgumentError('非法CIDR格式,正确格式示例:192.168.0.1/25'); } final ipStr = parts[0]; final prefixLength = int.tryParse(parts[1]); if (prefixLength == null || prefixLength < 0 || prefixLength > 32) { throw ArgumentError('前缀长度非法,IPv4前缀长度需在0~32之间'); } // 拆分IP段并转换为32位整数 final ipParts = ipStr.split('.'); if (ipParts.length != 4) { throw ArgumentError('IP格式非法,需为点分十进制四段格式'); } int ipInt = 0; for (int i = 0; i < 4; i++) { final segment = int.tryParse(ipParts[i]); if (segment == null || segment < 0 || segment > 255) { throw ArgumentError('IP段值非法,每段需在0~255之间'); } ipInt = (ipInt << 8) | segment; } // 计算掩码、网络地址、广播地址 final mask = prefixLength == 0 ? 0 : (0xFFFFFFFF << (32 - prefixLength)) & 0xFFFFFFFF; final networkAddr = ipInt & mask; final hostMask = prefixLength == 32 ? 0 : (1 << (32 - prefixLength)) - 1; final broadcastAddr = networkAddr | hostMask; // 计算起止IP,处理特殊前缀场景 int startIpInt; int endIpInt; if (prefixLength == 32) { // 32位前缀为单主机地址 startIpInt = ipInt; endIpInt = ipInt; } else if (prefixLength == 31) { // 31位前缀为点对点链路专用,两个地址均可使用 startIpInt = networkAddr; endIpInt = broadcastAddr; } else { // 常规场景排除网络地址、广播地址 startIpInt = networkAddr + 1; endIpInt = broadcastAddr - 1; } // 32位整数转回点分十进制IP String intToIp(int ipNum) { return [ (ipNum >> 24) & 0xFF, (ipNum >> 16) & 0xFF, (ipNum >> 8) & 0xFF, ipNum & 0xFF ].join('.'); } return '${intToIp(startIpInt)} - ${intToIp(endIpInt)}'; } // 测试用例 void main() { print(cidrToIpRange('192.168.0.1/25')); // 输出:192.168.0.1 - 192.168.0.126 print(cidrToIpRange('198.162.1.1/24')); // 输出:198.162.1.1 - 198.162.1.254 print(cidrToIpRange('10.0.0.5/32')); // 输出:10.0.0.5 - 10.0.0.5 }
内容的提问来源于stack exchange,提问作者rizwika
相关产品推荐
相关产品推荐

