客户端IP地址的最大长度

294

这个问题已经在这里有了答案。请查看https://dev59.com/iHNA5IYBdhLWcg3wPbSe。 - Arnkrishn
5
实际上,那篇帖子并没有太大的帮助。我们并没有使用Sql Server,而这篇帖子的答案已经很简明扼要,正是我所寻找的。 - Tony Eichelberger
7
@Andriyev那篇文章仅涉及IPv4。 - Android Eve
2
对于后来者 - 如果你有幸使用Postgres,他们有一个内置的IP数据类型,所以可以考虑使用。 - Wayne Werner
IPv6地址是8组4个十六进制数字,用7个:(39个字符)分隔。根据使用情况,它可以以其他格式书写。内部始终是128位。但您可能还想存储如何使用它以及可选设备名称,用于链路本地地址(它们以fe80:开头,可以附加%devname)。是的,您也可以将最后32位写成IPv4格式,因此用IPv4的15个字符替换这9个字符(45个字符)。但是,正如所说,它们仍然只是128位,以另一种格式编写给用户。这取决于上下文。 - Anders
8个回答

471

IPv6 的 39 个字符结构存在一个警告。 对于 IPv4 映射的 IPv6 地址,字符串可能会更长(超过 39 个字符)。以下是一个示例:

IPv6(39个字符):

ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:ABCD

IPv4-mapped IPv6(45个字符):

ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:192.168.158.190

注意: 最后的32位(对应IPv4地址)最多可以需要15个字符(因为IPv4使用4组1字节,并且格式化为四个范围在0-255之间的十进制数字,由点号(.)分隔,因此最大值为DDD.DDD.DDD.DDD)。

因此,正确的IPv6字符串最大长度为45个字符。

这实际上是我参加IPv6培训中的一道测验题。(我们都回答了39!)


6
在我看来,这是不正确的。根据https://tools.ietf.org/html/rfc5952#page-10和https://tools.ietf.org/html/rfc4291#section-2.5.5规定,IPv6映射地址最长为22个字符,因为它们总是采用::ffff:000.000.000.000的格式,并且必须缩短。 - oarsome
1
我想知道他是否真的像https://tools.ietf.org/html/rfc4291#section-2.5.5.1中所述,意思是“ipv6-compatible ipv4 address”。我从未在现实中见过这些。 - Dan Pritts
你可以在测验中争论,你以 :hex 形式存储 IPv4 而不是 IPv6,其中 39 再次正确。 - Joshua
1
IPv6地址不必缩短,但它们可以被缩短。所有这些地址都只是128位,即使它们使用了IPv4格式的部分进行书写。 - Anders

284

对于IPv4,你可以仅存储IP地址的4个原始字节(IP地址中每个点之间的数字都是0-255,即一个字节)。但是这样会产生翻译进出数据库的问题,不够简洁。

IPv6地址为128位(相比IPv4地址的32位),通常写为由冒号分隔的8组4位十六进制数字:2001:0db8:85a3:0000:0000:8a2e:0370:7334。以这种格式存储IPv6地址需要39个字符。

编辑:然而,有一个细节需要注意,关于IPv4映射IPv6地址的详细信息请参见@Deepak's回答。(正确的IPv6字符串最大长度为45个字符。)


5
一些数据库(至少包括PostgreSQL)具有原生的IP列类型,并可为您执行转换。 - gnud
4
我建议在“一段时间”内避免将IPv4和IPv6混合存储在数据库的同一字段中。IPv4仍然是默认标准,并且在未来的几年里将继续使用。在我曾经使用的老旧应用程序中,当需要向数据库添加IPv6地址时,这是作为一个单独的条目完成的。这样可以保留现有代码对IPv4地址的期望,并允许代码继续仅获取IPv4地址。对于代码的新部分,它们可以选择从查询中特别获取IPv4、IPV6或混合。 - Stan Graves
7
同样的原因,你不会将IPv4存储为4个字节。 - Matt Bridges
1
@MattBridges 你怎么知道我不会?以明文可读格式存储IP地址绝对没有任何用途。事实上,我会认为如果你保留原始格式,就可以轻松地执行数学计算,而不是在SQL查询中使用正则表达式等内容。 - Christian
2
如果您计划通过位掩码进行查询,那么显然应该存储为字节。如果每行额外的23个字节对您来说是一个问题,那么显然应该存储为字节。不确定问题出在哪里。 - Matt Bridges
显示剩余7条评论

28

如果你想处理标准符号中的IPV6地址,它包括8组由4个十六进制数字组成的组:

2001:0dc5:72a3:0000:0000:802e:3370:73E4

32个十六进制数字+7个分隔符=39个字符。

注意: 如果您还想保留作为IPv6地址映射的IPv4地址,则按照@Deepak建议,使用45个字符


1
实际上,这只是一个128位数字,您可以选择不同的方式将其打印出来。您还可以在地址中添加设备%device。 但是,如果压缩地址,则IPv6文本格式可以存储在39个字符或更少的字符中。但是,如果添加了%device和额外的(4*3+3) - (2*4+1)个字符(或一些位来建议打印时使用哪种格式),则会增加一些字符。 - Anders

13

从一个尝试了所有三种方法的人的经验来看,只需使用varchar(39)

略微不那么高效的存储远远超过在插入/更新时进行转换和在任何地方显示时进行格式化的任何好处。


大多数成熟的数据库都有存储IPv4和IPv6地址及其子网掩码的格式。我会使用这种格式。并且始终将其转换为适合用户的格式。是的,IPv6长度为128位,子网掩码也是如此(但对于IPv4而言可以缩减到7位数字,对于IPv6则最多可缩减到128位)。 - Anders

8

正如IPv6维基百科文章所述,IPv6地址通常写作八组由冒号(:)分隔的四个十六进制数字。

一个典型的IPv6地址:

2001:0db8:85a3:0000:0000:8a2e:0370:7334

这段文字长度为39个字符。IPv6地址长度为128位,因此你可以使用二进制(16)列,但我认为最好使用字母数字表示法。


然后你需要存储网络掩码。IPv4需要32位,而IPv6只需要8位(1字节)。 - Anders

4
如果你只是存储作为参考,你可以将它存储为字符串,但如果你想进行查找,例如查看IP地址是否在某个表中,你需要一个“规范表示”。将整个内容转换为(大)数字是正确的做法。IPv4地址可以存储为长整型(32位),但你需要一个128位的数字来存储IPv6地址。
例如,所有这些字符串实际上都是同一个IP地址:127.0.0.1,127.000.000.001,::1,0:0:0:0:0:0:0:1。

2

IPv4使用32位,格式如下:

255.255.255.255

我想这取决于你的数据类型,无论是仅使用CHAR类型将其存储为字符串还是使用数字类型。

IPv6使用128位。除非你要将其他信息包含在其中,否则IP不会比这更长。

IPv6被分为由冒号分隔的4个十六进制数字组成的集合,例如从维基百科引用的:

2001:0db8:85a3:0000:0000:8a2e:0370:7334

如果您希望这样做,可以将其存储为39个字符长的字符串,这是安全的。当然,还有其他简写地址的方法。一组零可以缩短为一个0,或者一组零可以通过双冒号完全隐藏。


不要忘记存储子网掩码。在IPv4上,你需要32个额外的比特位,在IPv6上只需要一个字节(0-128)。你可能还想存储首选的打印格式,例如输入到计算机中使用的格式。 - Anders

1

人们正在谈论字符,当一个IP地址可以被压缩成原始数据时。

因此,原则上,由于我们只使用IPv4(32位)或IPv6(128位),这意味着您最多需要128位的空间,或者128/8 = 16字节

这比建议的39个字节要少得多(假设字符集为ASCII)。

也就是说,您将不得不将IP地址解码和编码为/从原始数据中,这本身是一件微不足道的事情(我以前做过,参见PHP的ip2long()用于32位IP)。

编辑:inet_pton(及其相反的inet_ntop())可以满足您的需求,并且适用于两种地址类型。但请注意,在Windows上,它仅适用于PHP 5.3以上版本。


@Elipticalview,我觉得你根本没有读我的回答。我从未在任何地方提到过45字节!如果您将任何IPv4值(甚至是像您提到的那样的错误值)转换为原始数据,则它们不应超过4个字节-因为无论您有多少个点,它们总数应该总共达到4个数字,每个数字最多不超过255。 - Christian
您还可以将IPv6地址打印出来,其中最后32位写成IPv4地址。这将用43+3个字符替换24+1个字符。但是正如提到的那样,您可以将其存储为128位地址、网络掩码(值可高达128)、可选设备(长度取决于操作系统)以及一些用于首选格式的位以供用户打印。 - Anders

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接