用 C++ 写一个 Inet4Address 类
本文最后更新于 2024年10月3日 晚上
Inet4Address
在 .net 和 facebook/folly 中也叫做 IPAddress
。
(顺便黑一下,muduo 中居然把 SocketAddress
叫做 InetAddress
真是有失偏颇。
构造ip地址
ip 地址的构造,比较麻烦的地方就是网络序和主机序之间的问题。
我们的 raw ipv4 address 存储在一个 uint32_t
的整数中,按照 linux 官方手册中的描述,以下结构体表示 ipv4 address:
1 |
|
s_addr
是按网络序存储的,然而在下面的测试中,有与我预期不符合的地方:
1 |
|
我原先以为高位的 192 应该在 b3,而实际上在 b0。在 Java 中 的 Inet4Address.getAddress()
也有注释说明
1 |
|
(一开始没有理解这一点,我在 s_addr 存储的是 little-endian 值,以至于我引入了 redis 的 endianconv 作为工具函数,现在看来暂时没有用武之地了)
我们首先规定我们将使用 big-endian 存储 IP 地址,并统一使用
对于 IP 地址:b0.b1.b2.b3,我们用
0x b3 b2 b1 b0 来构造大端序
0x b0 b1 b2 b3 来构造小端序
我们允许使用者通过
Byte4
类型,也就是std::array<uint8_t, 4>
作为参数来构造Inet4Address
,前提是Byte4
参数是网络序:即对于 “192.168.0.1”, b0 = 192, b1 = 168, b2 = 0, b3 = 1
我们也允许使用者通过 NBO 的
uint32_t
类型的地址进行构造,这时候我们该用ntohl
或htonl
来实现。
特殊的 ip 地址
loopback address
环回地址。也就是127.0.0.1
这些地址在代码注释中有提供描述他们的 RFC 文档。
总结
因为理解的偏差,造轮子的时候走了一些远路(但不是歧路):
in_addr.s_addr
是否为 NBOb0 为 ipv4 的高8位地址,而不是 b3
引入 redis 的 endianconv,写了一些无用代码,希望以后会派上用场。
当然还有阅读 RFC 文档,理解这些特殊 IP 地址的定义和用途。