对于我正在编写的一个程序,我必须检查IP(将我连接到Internet的IP)是公共的还是私有的。因此,我需要区分IP是IPv4还是IPv6。
我想通过IP的长度来检查它:
conn, err := net.Dial("udp", "8.9.10.11:2342")
if err != nil {
fmt.Println("Error", err)
}
localaddr := conn.LocalAddr()
addr, _ := net.ResolveUDPAddr("udp", localaddr.String())
ip := addr.IP
fmt.Println(ip)
fmt.Println(len(ip))
字符串
我的IP地址是192.168.2.100,所以是IPv4,但是len(ip)告诉我长度是16,也就是IPv6。我错在哪里?是否存在任何其他方法来区分IPv4和IPv6,并且始终有效?
6条答案
按热度按时间swvgeqrz1#
jimt的答案是正确的,但相当复杂。我只检查
ip.To4() != nil
。由于文档中说“如果ip不是IPv4地址,To4返回nil”,当且仅当该地址是IPv4地址时,该条件应该返回true
。abithluo2#
accepted answer乘Evan(
ip.To4() != nil
)解决了这个问题。然而,有一些评论和其他答案检查表示是IPv4还是IPv6,并且它们并不总是准确的:有效的IPv4符号:
"192.168.0.1"
:基本"192.168.0.1:80"
:带端口信息有效的IPv6符号:
"::FFFF:C0A8:1"
:基本"::FFFF:C0A8:0001"
:前导零"0000:0000:0000:0000:0000:FFFF:C0A8:1"
:双冒号展开"::FFFF:C0A8:1%1"
:带区域信息"::FFFF:192.168.0.1"
:IPv4文字"[::FFFF:C0A8:1]:80"
:带端口信息"[::FFFF:C0A8:1%1]:80"
:带区域和端口信息所有这些情况(IPv4和IPv6列表)都将被
net
包视为IPv4地址。IPv6列表的IPv4文字变体将被govalidator视为IPv4。检查它是IPv4还是IPv6符号的最简单方法如下:
字符串
axzmvihb3#
IP的长度几乎总是16,因为
net.IP
的内部表示在两种情况下都是相同的。来自文档:请注意,在本文档中,将IP地址称为IPv4地址或IPv6地址是地址的语义属性,而不仅仅是字节片的长度:一个16字节的分片仍然可以是IPv4地址。
区分这两种类型取决于IP的初始化方式。查看
net.IPv4()
的代码,可以看到它被初始化为16个字节,其中前12个字节被设置为v4InV6Prefix
的值。字符串
其中
v4InV6Prefix
定义为:型
如果你想要一个可靠的区分,看看
net.IP.To4
的源代码是如何处理的:型
isZeros
未导出,因此必须在本地复制该代码。然后,您可以简单地执行与上面相同的操作,以确定您使用的是IPv4还是IPv6。e5nszbig4#
govalidator检查字符串中是否存在
:
。字符串
m1m5dgzv5#
我会使用net包中的.To4()、.To16()来查找它是IPv4还是IPv6地址。检查blog post。查看博客的最后一部分,例如可能对您有帮助。
5q4ezhmt6#
IPAddress Go library可以通过几行多态代码来实现这一点,可以同时使用IPv4和IPv6地址。Repository here .免责声明:我是项目经理。
它可以处理Adirio回答中列出的所有格式,以及其他格式。
IPv4有“私有”的概念,IPv6有“唯一本地”的概念,两者都有“链路本地”。
字符串
用你的例子“8.9.10.11:2342”,Adirio的列表和其他一些例子来试试:
型
输出量:
型