4个版本

使用旧的Rust 2015

0.1.3 2023年4月17日
0.1.2 2018年1月30日
0.1.1 2016年8月27日
0.1.0 2016年8月25日

#1074 in 网络编程

Download history 154/week @ 2024-03-13 205/week @ 2024-03-20 128/week @ 2024-03-27 171/week @ 2024-04-03 155/week @ 2024-04-10 526/week @ 2024-04-17 668/week @ 2024-04-24 427/week @ 2024-05-01 398/week @ 2024-05-08 387/week @ 2024-05-15 429/week @ 2024-05-22 401/week @ 2024-05-29 451/week @ 2024-06-05 383/week @ 2024-06-12 264/week @ 2024-06-19 373/week @ 2024-06-26

1,565每月下载量
3 个包中使用

MIT许可证

130KB
1.5K SLoC

Build Status npm cargo ruby

= IPAddress

IPAddress是一个库,旨在使IPv4和IPv6地址的使用变得简单、强大和愉快。它提供了一套完整的方法来处理IP地址,满足从简单脚本到完整网络设计的任何需求。

IPAddress应具有与以下语言的API相同(某些看起来很奇怪的)

  • ruby
  • rust
  • go / golang
  • javascript/typescript
  • java / xtend
  • java / kotlin
  • cpp
  • swift
  • .net csharp

文档是ruby的,希望也是rust的。

由于它起源于ruby/rust,这两种语言都不喜欢驼峰命名法,因此函数命名可能看起来很奇怪。

== 安装

使用rubygems安装库

$ gem install Construqt-ipaddress

然后您可以在程序中使用它

require 'rubygems' # 可选 require 'Construqt-ipaddress'

另一种方法是克隆git仓库

$ git clone git://github.com/mabels/ipaddress.git

然后安装库

$ cd ipaddress ipaddress$ rake install

使用rust安装库 $ cargo install ipaddress

或添加到您的Cargo.toml ipaddress = "0.1.1"

对于go

$ go get github.com/mabels/ipaddress/go/ipaddress

对于javascript

$ npm install ipaddress

它是一个位于包根目录的commonjs文件ipaddress.js,如果您的typescript,则有一个包含typescript源文件的src目录。

对于C++,您需要boost 1.54> 和 cmake 和 g++

$ cmake . && make

对于java

$ mvn package

目前我无法将我的工件发送到maven-central,因为签名和子密钥存在gpg问题。我将其发送到jcenter。

对于swift

$ swift build $ swift test

对于c#

$ dotnet restore $ dotnet build $ dotnet test $ dotnet build -c Release $ nuget push com.adviser.ipaddress.0.2.5.nupkg APIKEY -Source https://nuget.net.cn/api/v2/package

== 文档

代码完全使用RDoc进行文档编制。您可以使用Rake生成文档

ipaddress$ rake rdoc

最新文档可在http://rubydoc.info/gems/costruqt-ipaddress在线找到

https://docs.rs/ipaddress/0.1.1/ipaddress/struct.IPAddress.html

我需要探索如何将文档发布到npm

== IPv4

IPAddress::IPv4类用于处理IPv4类型地址。IPAddress与Ruby的IPAddr等其他IP地址库类似。然而,它的工作方式略有不同,我们将看到。

=== 创建新的IPv4地址

表示IP地址的常用方法是使用点分十进制形式,例如172.16.10.1,以及一个前缀,例如24,由斜杠分隔。

172.16.10.1/24

要创建一个新的IPv4对象,可以使用IPv4自己的类

ip = IPAddress::IPv4.new "172.16.10.1/24"

或者,以更简单的方式,使用IPAddress的解析方法

ip = IPAddress.parse "172.16.10.1/24"

它接受并解析任何类型的IP(IPv4、IPv6以及IPv4 IPv6映射地址)。

如果您喜欢语法糖,可以使用围绕IPAddress::parse构建的包装方法IPAddress()

ip = IPAddress "172.16.10.1/24"

您可以使用两种方式之一指定IPv4地址

IPAddress "172.16.10.1/24" IPAddress "172.16.10.1/255.255.255.0"

在此示例中,前缀/24和子网掩码255.255.255.0相同,您可以使用其中任何一个。

如果您没有明确指定前缀(或子网掩码),IPAddress认为您正在处理主机地址,而不是网络。因此,默认前缀将是/32,或255.255.255.255。例如

让我们声明一个主机地址

host = IPAddress::IPv4.new "10.1.1.1"

puts host.to_string #=> "10.1.1.1/32"

新创建的对象前缀为/32,这与我们创建以下内容相同

host = IPAddress::IPv4.new "10.1.1.1/32"

=== 处理IPv4地址

一旦创建,您可以获取IPv4对象的属性

ip = IPAddress("172.16.10.1/24")

ip.address #=> "172.16.10.1" ip.prefix #=> 24

如果您需要以IPv4格式检索子网掩码,可以使用IPv4#netmask方法

ip.netmask #=> "255.255.255.0"

一个特殊的属性IPv4#octets可用于获取IP地址中的四个十进制八位字节

ip.octets #=> [172,16,10,1]

快捷方法IPv4#[]提供了访问指定范围内的给定八位字节的方法

ip[1] #=> 16

如果您需要以规范形式打印IPv4地址,可以使用IPv4#to_string

ip.to_string #=> "172.16.10.l/24"

=== 修改子网掩码

创建IPv4对象后,您可以设置新的前缀(子网掩码)

ip.prefix = 25

ip.to_string #=> "172.16.10.l/25"

如果您需要使用IPv4格式的子网掩码,可以通过使用IPv4#netmask=方法实现

ip.netmask = "255.255.255.252"

ip.to_string #=> "172.16.10.1/30"

=== 与网络、广播和地址一起工作

处理IP地址时的一些非常重要的话题是网络和网络广播的概念,以及包含在范围内的地址。

当您指定一个如“172.16.10.1/24”的IPv4地址时,您实际上正在处理两种不同的信息

  • IP地址本身,“172.16.10.1”
  • 指示网络的子网掩码

网络号是主机部分全部为零的IP地址。在我们的例子中,因为前缀是24,我们确定我们的网络号为最后8位(32-24)全部为零。因此,IP地址“172.16.10.1/24”属于网络“172.16.10.0/24”。

这非常重要,例如,IP“172.16.10.1/16”与前面的例子非常不同,属于完全不同的网络“172.16.0.0/16”。

==== 网络

使用IPAddress很容易计算IP地址的网络

ip = IPAddress "172.16.10.1/24"

net = ip.network #=> #<IPAddress::IPv4:0xb7a5ab24 @octets=[172, 16, 10, 0], @prefix=24, @address="172.16.10.0"> net.to_string #=> "172.16.10.0/24"

方法IPv4#network从原始对象计算后的网络号码创建一个新的IPv4对象。我们在这里想强调的是,网络地址是一个完全合法的IPv4地址,只是恰好主机部分全为零。

您可以使用方法IPv4#network?来检查一个IP地址是否是网络地址

ip1 = IPAddress "172.16.10.1/24" ip2 = IPAddress "172.16.10.4/30"

ip1.network? #=> false ip2.network? #=> true

==== 广播地址

广播地址与网络号码相反:当网络号码的主机部分全为零时,广播地址的主机部分全为1。例如,IP "172.16.10.1/24" 的广播地址为 "172.16.10.255/24",而IP "172.16.10.1/16" 的广播地址为 "172.16.255.255/16"。

方法IPv4#broadcast的行为与它的#network对应方法相同:它创建一个新的IPv4对象来处理广播地址

ip = IPAddress "172.16.10.1/24"

bcast = ip.broadcast #=> #<IPAddress::IPv4:0xb7a406fc @octets=[172, 16, 10, 255], @prefix=24, @address="172.16.10.255"> bcast.to_string #=> "172.16.10.255/24"

==== 地址、范围和迭代器

因此,我们看到子网掩码本质上指定了一个包含在网络中的IP地址范围:从网络号码到广播地址之间的所有地址。IPAddress有许多方法可以在这组地址之间迭代。让我们从IPv4#each开始,它迭代一个范围内的所有地址

ip = IPAddress "172.16.10.1/24"

ip.each do |addr| puts addr end

重要的是要注意,原始IP是主机IP、网络号码(或广播地址)并不重要:#each方法只考虑原始IP指定的范围。

如果您只想迭代主机IP,请使用IPv4#each_host方法

ip = IPAddress "172.16.10.1/24"

ip.each_host do |host| puts host end

方法IPv4#first和IPv4#last分别返回包含范围中第一个和最后一个主机地址的新对象

ip = IPAddress "172.16.10.100/24"

ip.first.to_string #=> "172.16.10.1/24"

ip.last.to_string #=> "172.16.10.254/24"

=== IP特殊格式

IPAddress库提供了一套完整的方法来访问IPv4地址的特殊格式,如二进制、32位无符号整数、数据和十六进制。

让我们以以下IPv4地址为例

ip = IPAddress "172.16.10.1/24"

ip.address #=> "172.16.10.1"

在此需要强调的是,所有这些转换方法只考虑IPv4对象的地址部分,而不考虑前缀(子网掩码)。

因此,要表示二进制格式的地址,请使用IPv4#bits方法

ip.bits #=> "10101100000100000000101000000001"

要计算IP地址的32位无符号整数格式,请使用IPv4#to_u32方法

ip.to_u32 #=> 2886732289

此方法相当于Unix调用pton(),以所谓的+网络字节序+表示法表示IP地址。然而,如果您想要在网络套接字上传输IP,您可能需要使用IPv4#data方法将其转换为数据格式

ip.data #=> "\254\020\n\001"

最后,您可以将IPv4地址转换为适用于IPv4-IPv6映射地址的格式

ip.to_ipv6 #=> "ac10:0a01"

=== 类别网络

IPAddress允许您使用旧的和已弃用的(但显然仍然流行)类别网络概念创建和操作对象。

类别网络和地址没有前缀:它们的子网掩码由地址唯一标识,因此分为类别。根据RFC 791,这些类别是

  • 类别A,从0.0.0.0到127.255.255.255
  • 类别B,从128.0.0.0到191.255.255.255
  • 类别C,从192.0.0.0到255.255.255.255

由于此处仅考虑计算默认前缀编号的类别网络,因此不考虑类别D和E。

要从IP地址创建类别IP和前缀,请使用IPv4::parse_classful方法

类别IP

ip = IPAddress::IPv4::parse_classful "10.1.1.1"

ip.prefix #=> 8

该方法自动创建了一个新的IPv4对象,并将其分配了正确的前缀。

您可以轻松检查IPv4对象属于哪个CLASSFUL网络

ip = IPAddress("10.0.0.1/24") ip.a? #=> true

ip = IPAddress("172.16.10.1/24") ip.b? #=> true

ip = IPAddress("192.168.1.1/30") ip.c? #=> true

请注意,这些方法仅检查IP地址部分,与其前缀无关,因为CLASSFUL网络没有前缀的概念。

有关CLASSFUL网络的更多信息,请访问{维基百科页面}http://en.wikipedia.org/wiki/Classful_network

=== 使用IPAddress进行网络设计

IPAddress包含许多有用的方法,可以操作IPv4和IPv6网络,并进行一些基本的网络设计。

==== 子网划分

子网划分是将网络划分为更小的(在主机容量方面)网络的过程,称为子网,这样它们都共享一个共同的根,即起始网络。

例如,如果您有网络"172.16.10.0/24",我们可以将其划分为4个更小的子网。新的前缀将是/26,因为4是2的2次方,因此我们向网络前缀中添加2位(24+2=26)。

使用IPAddress进行子网划分很简单。您实际上有两个选项

  • IPv4#subnet: 指定新的前缀
  • IPv4#split: 告诉IPAddress您要创建多少个子网。

让我们先看看IPv4#subnet。假设您有网络"172.16.10.0/24",并想要将其划分为/26网络。使用IPAddress非常简单

network = IPAddress "172.16.10.0/24"

subnets = network.subnet(26)

subnets.map{|i| i.to_string} #=> ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26", "172.16.10.192/26"]

如您所见,已创建了一个数组,其中包含代表新子网的4个新的IPv4对象。

创建子网的另一种方法是告诉IPAddress您希望有多少个子网,并让库为您计算新的前缀。

让我们看看IPv4#split方法是如何工作的。假设您想要4个新的子网

network = IPAddress("172.16.10.0/24")

subnets = network.split(4)

subnets.map{|i| i.to_string} #=> ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26", "172.16.10.192/26"]

嘿,这与之前的结果相同!这实际上是有意义的,因为这两个操作是互补的。当您使用IPv4#subnet与新的前缀时,IPAddress总是会创建一个子网的数量,这个数量是2的幂。这相当于使用IPv4#split与2的幂。

IPv4#split真正出色的地方是所谓的“不均匀子网划分”。您不仅可以将网络划分为2的幂次方数量的子网:IPAddress让您创建任意数量的子网,并且它将尝试以最佳方式组织新创建的网络,从而实现高效的地址分配。

下面这个例子可以说明一切。让我们使用之前示例中的相同网络

network = IPAddress("172.16.10.0/24")

我们如何将此网络划分为3个子网?非常简单

subnets = network.split(3)

subnets.map{|i| i.to_string} #=> ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/25"]

如您所见,IPAddress尝试进行良好的分配,填充了原始网络的所有地址空间。没有必要将网络划分为“172.16.10.0/26”、“172.16.10.64/26”和“172.16.10.128/26”这样的3个子网,因为您最终会有“172.16.10.192/26”的浪费(此外,我假设我不会需要一个Ruby库来执行不高效的IP分配,因为我自己已经做得很好了 ;) )。

我们可以进一步将其划分为11个子网

network.split(11) #=> ["172.16.10.0/28", "172.16.10.16/28", "172.16.10.32/28", "172.16.10.48/28", "172.16.10.64/28", "172.16.10.80/28", "172.16.10.96/28", "172.16.10.112/28", "172.16.10.128/27", "172.16.10.160/27", "172.16.10.192/26"]

如您所见,大多数网络都是/28,还有一些/27和一个/26来填充剩余的空间。

==== 总结

汇总(或聚合)是指将两个或多个网络合并在一起以检查是否存在一个包含所有这些网络的超网。如果存在,则称此超网为汇总(或聚合)网络。理解这一点非常重要,即只有在聚合网络中没有漏洞的情况下,或者换句话说,如果给定的网络完全填充超网的地址空间时,才会发生汇总。因此,两个规则是

  1. 聚合网络必须包含原始网络的所有IP地址;

  2. 聚合网络必须只包含原始网络的IP地址;

一些例子将有助于澄清上述内容。以以下两个网络为例

ip1 = IPAddress("172.16.10.0/24") ip2 = IPAddress("172.16.11.0/24")

如果我们更改前缀,这两个网络可以用一个IP地址网络来表示。让Ruby来做这项工作

IPAddress::IPv4::summarize(ip1,ip2).map(&:to_string) #=> "172.16.10.0/23"

我们注意到网络“172.16.10.0/23”包括上述网络中指定的所有地址,并且(更重要的是)只包括这些地址。

如果我们用以下网络汇总+ip1+和+ip2+

"172.16.0.0/16"

我们将满足上述规则#1,但不满足规则#2。因此

"172.16.0.0/16"

不是+ip1+和+ip2+的聚合网络。

如果无法为所有原始网络计算单个聚合网络,则该方法将返回一个包含所有找到的聚合网络的数组。例如,以下四个网络可以聚合到一个单独的/22中

ip1 = IPAddress("10.0.0.1/24") ip2 = IPAddress("10.0.1.1/24") ip3 = IPAddress("10.0.2.1/24") ip4 = IPAddress("10.0.3.1/24")

IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string} #=> ["10.0.0.0/22"]

但是以下网络不能汇总到一个单独的网络中

ip1 = IPAddress("10.0.1.1/24") ip2 = IPAddress("10.0.2.1/24") ip3 = IPAddress("10.0.3.1/24") ip4 = IPAddress("10.0.4.1/24")

IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string} #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]

在这种情况下,两个可汇总的网络已聚合到一个单独的/23中,而其他两个网络保持不变。

==== 超网技术

超网技术与聚合不同,因为它只对一个单一的网络进行操作,并返回一个表示超网的新单个IPv4对象。

超网技术与子网划分类似,但结果是具有更小前缀(更大的主机空间)的网络。例如,给定网络

ip = IPAddress("172.16.10.0/24")

你可以用新的/23前缀进行超网划分

ip.supernet(23).to_string #=> "172.16.10.0/23"

然而,如果你用/22前缀进行超网划分,网络地址将改变

ip.supernet(22).to_string #=> "172.16.8.0/22"

这是因为"172.16.10.0/22"不再是网络,而是一个主机地址。

== IPv6

IPAddress不仅对IPv4地址非常出色,而且也非常适合处理IPv6地址族!让我们一起看看如何在我们的项目中使用它。

=== IPv6地址

IPv6地址长128位,与只有32位的IPv4地址相比。IPv6地址通常写成由四个十六进制数字组成的八组,每组代表16位或两个八位字节。例如,以下是一个有效的IPv6地址

2001:0db8:0000:0000:0008:0800:200c:417a

IPv6地址中的字母通常按照RFC的要求写成小写。您可以使用大写字母创建新的IPv6对象,但它们将被转换。

==== 压缩

由于IPv6地址非常长,因此可以使用一些简化和压缩方法来缩短它们。

  • 前导零:可以省略组内的所有前导零:“0008”将变成“8”

  • 连续零的字符串可以用字符串“::”替换。这只能应用一次。

使用压缩,上面的IPv6地址可以缩短为以下等效地址

2001:db8::8:800:200c:417a

这种简短版本通常用于人类表示。

==== 网络掩码

就像我们过去使用IPv4地址一样,IPv6地址可以使用前缀表示法来指定子网掩码

2001:db8::8:800:200c:417a/64

"/64"部分表示地址的前64位表示网络部分,后64位表示主机部分。

=== 使用IPAddress与IPv6地址

我们刚才看到的所有IPv6表示法在创建新的IPv6地址时都是完全可行的

ip6 = IPAddress "2001:0db8:0000:0000:0008:0800:200C:417A"

ip6 = IPAddress "2001:db8:0:0:8:800:200C:417A"

ip6 = IPAddress "2001:db8:8:800:200C:417A"

这三个都给出了相同的IPv6对象。IPv6的默认子网掩码为128,因为IPv6地址没有像IPv4地址那样的类。如果您想要不同的掩码,您可以明确指定它

ip6 = IPAddress "2001:db8::8:800:200c:417a/64"

使用相应的方法访问地址部分和前缀

ip6 = IPAddress "2001:db8::8:800:200c:417a/64"

ip6.address #=> "2001:0db8:0000:0000:0008:0800:200c:417a"

ip6.prefix #=> 64

可以使用IPv6#compressed方法获取IPv6地址的压缩版本

ip6 = IPAddress "2001:0db8:0000:0000:0008:200c:417a:00ab/64"

ip6.compressed #=> "2001:db8::8:800:200c:417a"

=== 处理IPv6地址

使用IPv6#groups方法可以非常容易地访问构成IPv6地址的组

ip6 = IPAddress "2001:db8::8:800:200c:417a/64"

ip6.groups #=> [8193, 3512, 0, 0, 8, 2048, 8204, 16762]

与IPv4地址一样,可以使用IPv6#[]快捷方法访问每个单独的组

ip6[0] #=> 8193 ip6[1] #=> 3512 ip6[2] #=> 0 ip6[3] #=> 0

请注意,每个16位组以十进制形式表示。您还可以使用IPv6#hexs方法将组转换为十六进制格式

ip6.hexs #=> ["2001", "0db8", "0000", "0000", "0008", "0800", "200c", "417a"]

其他一些方法可以将IPv6地址转换为十进制表示形式,使用IPv6.to_i

ip6.to_i #=> 42540766411282592856906245548098208122

或转换为十六进制表示

ip6.to_hex #=> "20010db80000000000080800200c417a"

要打印出可读的IPv6地址,请使用IPv6#to_s, IPv6#to_string和IPv6#to_string_uncompressed方法

ip6 = IPAddress "2001:db8::8:800:200c:417a/64"

ip6.to_string #=> "2001:db8::8:800:200c:417a/96"

ip6.to_string_uncompressed #=> "2001:0db8:0000:0000:0008:0800:200c:417a/96"

如您所见,IPv6.to_string打印出压缩形式,而IPv6.to_string_uncompressed使用扩展版本。

==== 压缩与解压缩

如果您有一个表示IPv6地址的字符串,您可以使用两个类方法IPv6::expand和IPv6::compress轻松地进行压缩和解压缩。

例如,假设您有一个以下未压缩的IPv6地址

ip6str = "2001:0DB8:0000:CD30:0000:0000:0000:0000"

这是压缩版本

IPAddress::IPv6.compress ip6str #=> "2001:db8:0:cd30::"

另一种方式同样有效

ip6str = "2001:db8:0:cd30::"

IPAddress::IPv6.expand ip6str #=> "2001:0DB8:0000:CD30:0000:0000:0000:0000"

这些方法可以在您不想仅为了扩展或压缩地址而创建新对象时使用(尽管实际上在内部创建了一个新对象)。

=== 从其他格式创建新的IPv6地址

您可以从除了表示冒号十六进制组的字符串以外的其他格式创建新的IPv6地址。

例如,如果您有一个数据流,您可以使用IPv6::parse_data,如下例所示

data = " \001\r\270\000\000\000\000\000\b\b\000 \fAz"

ip6 = IPAddress::IPv6::parse_data data ip6.prefix = 64

ip6.to_string #=> "2001:db8::8:800:200c:417a/64"

新的IPv6地址也可以从一个无符号的128位整数创建

u128 = 42540766411282592856906245548098208122

ip6 = IPAddress::IPv6::parse_u128 u128 ip6.prefix = 64

ip6.to_string #=>"2001:db8::8:800:200c:417a/64"

最后,新的IPv6地址可以从一个十六进制字符串创建

hex = "20010db80000000000080800200c417a"

ip6 = IPAddress::IPv6::parse_hex hex ip6.prefix = 64

ip6.to_string #=> "2001:db8::8:800:200c:417a/64"

=== 特殊的IPv6地址

某些IPv6地址具有特殊含义,并以特殊形式表示,与常规IPv6地址大不相同。IPAddress内置了对未指定、环回和映射IPv6地址的支持。

==== 未指定地址

所有位都为零的地址称为未指定地址(对应于IPv4中的0.0.0.0)。它应该像这样

0000:0000:0000:0000:0000:0000:0000:0000

但是,在使用压缩的情况下,通常只写两个冒号

::

或者,指定子网掩码

::/128

使用IPAddress,通过其子类创建一个新的未指定IPv6地址

ip = IPAddress::IPv6::Unspecified.new

ip.to_string #=> "::/128"

您可以通过使用IPv6#unspecified?方法轻松检查IPv6对象是否为未指定地址

ip.unspecified? #=> true

未指定IPv6地址也可以通过包装方法创建,就像我们之前看到的那样

ip = IPAddress "::"

ip.unspecified? #=> true

此地址绝不能分配给接口,仅在使用软件之前在应用程序已学习到适合挂起连接的主机源地址时使用。路由器不得转发具有未指定地址的数据包。

==== 环回地址

环回地址是单播本地主机地址。如果主机中的应用程序向此地址发送数据包,IPv6堆栈将在同一虚拟接口上循环这些数据包。

环回地址的表达形式如下

::1

或者,使用它们适当的前缀

::1/128

至于未指定地址,IPv6环回可以通过调用IPAddress的自身类来创建

ip = IPAddress::IPv6::Loopback.new

ip.to_string #=> "::1/128"

或通过使用包装器

ip = IPAddress "::1"

ip.to_string #=> "::1/128"

使用IPv6#loopback?方法检查地址是否为环回非常简单

ip.loopback? #=> true

IPv6环回地址对应于IPv4中的127.0.0.1。

==== 映射地址

它通常被识别为IPv4映射IPv6地址,这是一种有助于从IPv4过渡到IPv6的特殊IPv6地址。地址的结构如下

::ffff:w.y.x.z

其中w.x.y.z是一个正常的IPv4地址。例如,以下是一个映射IPv6地址

::ffff:192.168.100.1

IPAddress在处理映射IPv6地址方面非常强大,因为IPv4部分作为正常的IPv4对象存储在内部。让我们看看一些例子。要创建一个新的映射地址,只需使用类构建器本身即可

ip6 = IPAddress::IPv6::Mapped.new "::ffff:172.16.10.1/128"

或者只需使用包装方法

ip6 = IPAddress "::ffff:172.16.10.1/128"

让我们检查它是否真的是一个映射地址

ip6.mapped? #=> true

ip6.to_string #=> "::ffff:172.16.10.1/128"

现在使用+ipv4+属性,我们可以轻松访问映射IPv6地址的IPv4部分

ip6.ipv4.address #=> "172.16.10.1"

在内部,IPv4地址以两个16位组的形式存储。因此,IPv6地址的所有常规方法都正常工作

ip6.to_hex #=> "00000000000000000000ffffac100a01"

ip6.address #=> "0000:0000:0000:0000:0000:ffff:ac10:0a01"

映射IPv6也可以通过指定以下格式的地址来创建

ip6 = IPAddress "::172.16.10.1"

也就是说,两个冒号和IPv4地址。然而,根据RFC,将在开头自动添加ffff组

ip6.to_string => "::ffff:172.16.10.1/128"

使其成为映射IPv6兼容地址。

== 为什么不使用IPAddr?

IPAddr是随Ruby标准库一起提供的IP地址库。我们发现这个库,尽管写得很好,但并不适合我们的所有需求,而且不够灵活。

以下是一些您无法使用IPAddr执行的操作的快速示例

  • 存储地址和前缀信息
  • 快速找到网络的广播地址
  • 迭代主机
  • 执行子网划分或网络聚合

许多方法和程序已经过时,被IETF宣布为废弃,并且一些其他方法在实现中存在错误。

此外,IPAddress更加健壮,并且比IPAddr快约50%,同时提供具有逻辑分离和面向对象结构的有机API。

我们希望IPAddress能够解决所有这些问题,满足您在网络编程中的所有需求。

== 版权

版权所有(c)2009-2011 Marco Ceresa。详情请见LICENSE。版权所有(c)2015-2017 Meno Abels。详情请见LICENSE。

依赖项

~2.5–3.5MB
~64K SLoC