gpt4 book ai didi

java - 从 CIDR 表示法到 IP 地址/子网掩码(点十进制)的转换

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:24:39 24 4
gpt4 key购买 nike

 /*
* RFC 1518, 1519 - Classless Inter-Domain Routing (CIDR)
* This converts from "prefix + prefix-length" format to
* "address + mask" format, e.g. from xxx.xxx.xxx.xxx/yy
* to xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy.
*/
static private String normalizeFromCIDR(final String netspec)
{
final int bits = 32 - Integer.parseInt(netspec.substring(netspec.indexOf('/')+1));
final int mask = (bits == 32) ? 0 : 0xFFFFFFFF - ((1 << bits)-1);

return netspec.substring(0, netspec.indexOf('/') + 1) +
Integer.toString(mask >> 24 & 0xFF, 10) + "." +
Integer.toString(mask >> 16 & 0xFF, 10) + "." +
Integer.toString(mask >> 8 & 0xFF, 10) + "." +
Integer.toString(mask >> 0 & 0xFF, 10);
}

这是apache james中的一个函数,可以将ip转换成指定的格式。你能解释一下函数内部发生了什么吗?对这种移位和转换感到困惑。提前致谢。

最佳答案

按位运算乍看之下可能不是最直观的,但一旦您掌握了它,您就会发现它们非常容易理解。我将尝试解释此代码在 172.16.0.1/23 的示例中的作用作为netspec字符串。

Part1 - CIDR 到二进制

目标是根据给定的 CIDR 前缀长度对子网掩码进行二进制表示。 CIDR 前缀长度只是一个数字 1子网掩码中的位。第一行

final int bits = 32 - Integer.parseInt(netspec.substring(netspec.indexOf('/')+1));

通过获取/的索引找到CIDR前缀长度并解析其后的整数(在我的示例中为 23)。这个数字从 32 中减去得到一个数字 0在子网掩码中——这些位也称为主机位。

在这个例子中,我们知道我们正在处理 /23前缀及其子网掩码应如下所示:

n represents network (16 bits for class B network), s represents subnet, h represents host. For us network and subnet bits are functionally the same, but I made a distinction just to be precise. Our interest is just in host bits (number of it).

nnnnnnnn nnnnnnnn sssssssh hhhhhhhh
11111111 11111111 11111110 00000000

做到这一点的最简单方法是拥有所有 1 的 32 位二进制数s 并用 0 “填充”最后 9 位.这是第二行出现的地方:

You can ignore the bits == 32 check since it is not that relevant and probably is there just as a optimization.

//final int mask = (bits == 32) ? 0 : 0xFFFFFFFF - ((1 << bits)-1); 
final int mask = 0xFFFFFFFF - ((1 << 9)-1);

0xFFFFFFFF将为您提供所有 1 的 32 位二进制数秒。 1左移 9 位 ( 1 << bits ) 会给你 512 和 512 - 1二进制是111111111 :

  1 << 9                               10 00000000
- 1 1
--------------------------------------------------
1 11111111

当您减去这些值时,您将得到二进制的子网掩码:

  0xFFFFFFFF = 11111111 11111111 11111111 11111111
- (1 << 9)-1 = 1 11111111
--------------------------------------------------
11111111 11111111 11111110 00000000

这正是我们想要的网络掩码。

注意:这可能不是计算二进制值的最直观方法。我喜欢从全 1 的二进制数开始,并且 signed int 中的数字的十进制值为 -1 .然后我只是将它向左移动主机位的数量,就是这样。 (此外,如果您要处理大于 32 位的整数,您可以使用 0xFFFFFFFF 对其进行屏蔽):

(-1 << 9) & 0xFFFFFFFF

Part2 - 二进制转点分十进制

其余代码将二进制值转换为点分十进制表示形式 — 255.255.254.0。

return netspec.substring(0, netspec.indexOf('/') + 1) +  // part of the netspec string before '/' -> IP address
Integer.toString(mask >> 24 & 0xFF, 10) + "." + // 11111111 & 0xFF = 0xFF
Integer.toString(mask >> 16 & 0xFF, 10) + "." + // 1111111111111111 & 0xFF = 0xFF
Integer.toString(mask >> 8 & 0xFF, 10) + "." + // 111111111111111111111110 & 0xFF = 0xFE
Integer.toString(mask >> 0 & 0xFF, 10); // 11111111111111111111111000000000 & 0xFF = 0x00

返回语句由几个串联的字符串组成,以 IP 地址开头,然后是每个八位字节的十进制表示形式。二进制掩码右移 (4-n)*8位(其中 n 是八位字节数)并使用二进制 AND 和 0xFF 你只得到最后 8 位,然后由 Integer.toString 解析.

结果是172.16.0.1/255.255.254.0 .

关于java - 从 CIDR 表示法到 IP 地址/子网掩码(点十进制)的转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23385765/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com