【计算机网络】第 12 篇:IPv6 详解——地址格式、地址类型与双栈网络

系列: 从 0 开始学习计算机网络

适合读者: 计算机专业学生、Java 后端学习者、希望理解现代网络部署的开发者

本文关键词: IPv6、128 位地址、链路本地地址、AAAA 记录、双栈网络、Happy Eyeballs

一、引言:为什么现在还需要学习 IPv6?

我们平时接触的很多网络配置仍然使用 IPv4 地址,例如 192.168.1.10。但 IPv4 地址只有 32 位,随着联网设备和服务数量增长,可供分配的 IPv4 地址空间已经十分紧张。

IPv6 将地址长度扩展为 128 位,提供了大得多的地址空间,也对报文首部、地址自动配置和邻居发现等机制作了调整。它不是把 IPv4 地址简单加长,而是新一代互联网协议。

不过,理解 IPv6 不能只停留在"地址更长"。开发者还需要知道:

  • IPv6 地址应该如何阅读和缩写?
  • fe80::、::1、2001:... 这类地址分别有什么用途?
  • DNS 的 AAAA 记录与 A 记录有什么区别?
  • 当一台电脑同时支持 IPv4 和 IPv6 时,客户端会怎样选择连接?
  • 为什么域名能解析出 IPv6 地址,却不一定能通过 IPv6 访问服务?

本文聚焦地址格式、常见地址类型和双栈访问,不再重复前文的子网掩码计算、路由基础、TCP 握手挥手或通用网络排查命令。

二、IPv6 地址长什么样?

2.1 128 位地址如何表示?

IPv4 地址是 32 位,通常写成四个十进制数字,例如:

text 复制代码
192.168.1.10

IPv6 地址是 128 位,通常写成 8 组十六进制字段,每组 16 位,字段之间用冒号分隔:

text 复制代码
2001:0db8:0000:0000:0000:0000:0000:0001

每组 16 位,也就是 4 个十六进制数字。十六进制中的一个数字表示 4 位,因此一组最多写 4 个十六进制字符。

上面地址的每组都可以用 0000 表示零字段。为了让地址更易读,IPv6 允许使用缩写规则。

2.2 IPv6 地址的三条常用缩写规则

规则一:每组开头的 0 可以省略。

text 复制代码
0db8  -> db8
0001  -> 1
0000  -> 0

注意,只能省略字段开头的零,不能把字段中间或末尾的零随意删掉。

规则二:连续的零字段可以用 :: 压缩。

text 复制代码
2001:0db8:0000:0000:0000:0000:0000:0001

可以缩写为:

text 复制代码
2001:db8::1

:: 表示一个或多个连续的 0000 字段。

规则三:同一个地址中,:: 最多出现一次。

例如:

text 复制代码
2001:db8::1:0:0:1

这是合法的缩写形式;但不能把同一地址中的两段零字段分别写成两个 ::,因为解析时无法确定每个 :: 应该补回多少组零。

RFC 5952 给出了建议使用的规范文本形式。实际写地址时,推荐使用小写十六进制、去掉字段前导零,并将最长的一段连续零字段压缩;若有多段同样长的零字段,选择最靠左的一段。单独一个零字段通常写作 0,而不是用 :: 压缩。

2.3 2001:db8::1 是真实服务器地址吗?

这是一个非常值得注意的细节。

2001:db8::/32 是专门用于文档、教程和示例的 IPv6 前缀。因此,本文中的 2001:db8::1 只是讲解格式的示例,不应被当作可在公网访问的真实服务器地址。

写技术文章、配置示例和教学代码时,使用文档专用地址可以避免误把示例当成真实目标。

2.4 /64 是什么意思?

IPv6 地址也可以使用前缀长度表示网络前缀,例如:

text 复制代码
2001:db8:1234:5678::/64

/64 表示地址最左侧的 64 位属于前缀,剩余 64 位属于该前缀下的接口标识部分。

许多普通终端网络使用 /64 前缀,尤其是在无状态地址自动配置(SLAAC)场景中。但不能据此断言所有 IPv6 网络都必须使用 /64:点到点链路、特殊用途网络和不同部署设计可能采用其他前缀长度。

三、IPv6 常见地址类型:看到前缀,先判断用途

IPv6 不同地址并不是"格式不同的普通公网 IP"。它们的用途和可达范围可能完全不同。以下是学习和排障时最常见的几类。

3.1 全球单播地址(Global Unicast Address)

全球单播地址用于全球范围的单播通信。当前常见的全球单播分配空间位于 2000::/3,但不能据此认为其中每个地址都已经分配或都能从公网访问。

例如:

text 复制代码
2001:4860:4860::8888

这是一个常见的公共 DNS 服务 IPv6 地址示例。真实可达性仍然取决于网络连接、路由和目标服务状态。

链路本地地址的前缀是:

text 复制代码
fe80::/10

它用于同一链路上的邻居通信,例如主机与本地链路上的路由器进行邻居发现。路由器不会把链路本地地址作为普通目的地址转发到其他链路。

IPv6 启用的接口通常会有链路本地地址,即使设备没有配置全球单播地址,也可能已经有链路本地地址。

因此,看到 fe80:: 开头的地址时,不要把它直接当作公网服务器地址。

3.3 唯一本地地址(Unique Local Address,ULA)

唯一本地地址使用 fc00::/7 前缀空间,常用于组织或站点内部通信,不应被当作全球公网可路由地址。

在常见的本地生成部署中,地址通常来自 fd00::/8。ULA 与 IPv4 私有地址在使用场景上有相似之处,但两者的具体分配规则并不完全相同。

3.4 未指定地址与回环地址

两个容易混淆的特殊地址:

地址 含义
::/128,常写作 :: 未指定地址,表示尚未指定有效的源地址;不是普通通信的目标地址
::1/128,常写作 ::1 回环地址,指向本机自身,类似 IPv4 的 127.0.0.1

例如,服务监听在 ::1 上,通常表示它只接受通过本机 IPv6 回环接口访问的连接,并不意味着其他机器能访问它。

3.5 组播地址与任播地址

IPv6 的组播地址使用:

text 复制代码
ff00::/8

组播用于将数据发送给一组加入相应组播组的接口。IPv6 没有 IPv4 那样的广播地址,许多原先依赖广播完成的局域网功能,在 IPv6 中由组播和邻居发现等机制实现。

任播(Anycast)则是把同一个单播格式的地址配置给多个接口,网络将数据路由到其中一个合适的接口。任播常用于把请求引导到一组服务节点中的某一个,但它不是一种独立的地址文本格式。

四、IPv6 如何自动配置地址?

IPv6 主机获得地址不只有一种方式。常见机制包括:

  • SLAAC(无状态地址自动配置): 主机根据路由器通告的前缀等信息,按照相关规则配置地址。
  • DHCPv6: 通过 DHCPv6 协议获取地址或其他网络配置信息,具体使用方式取决于网络部署。
  • 手动配置: 管理员在设备或服务器上配置地址。

这些机制可以在同一网络中按部署策略配合使用。不要简单地认为"IPv6 一定不用 DHCP",也不要认为"IPv6 地址一定由路由器直接分配"。

邻居发现不是 IPv4 ARP 的简单改名

在 IPv4 局域网中,ARP 常用于根据 IPv4 地址查询对应的链路层地址。IPv6 不使用 ARP,而是通过 IPv6 Neighbor Discovery(邻居发现) 完成邻居地址解析、路由器发现和可达性维护等功能。它基于 ICMPv6 消息工作。

这里不展开邻居发现的报文细节,因为本篇重点是 IPv6 地址和双栈访问;只需要先记住:IPv6 的邻居发现机制与 IPv4 的 ARP 有相似的用途,但不是同一个协议。

五、DNS 中的 A 和 AAAA:有 IPv6 地址记录就能访问吗?

DNS 负责把域名映射到相关资源记录。IPv4 和 IPv6 对应不同的地址记录类型:

  • A 记录: 存储 IPv4 地址。
  • AAAA 记录: 存储 IPv6 地址。

例如,一个域名可以同时拥有 A 记录和 AAAA 记录,也可以只配置其中一种。DNS 查询本身使用 IPv4 还是 IPv6 作为传输方式,与查询结果中存放的是 IPv4 地址还是 IPv6 地址没有必然绑定关系。

可以使用下面的命令查询 AAAA 记录:

bash 复制代码
nslookup -type=AAAA example.com

也可以分别强制 curl 使用 IPv4 或 IPv6 测试 HTTPS 访问:

bash 复制代码
curl -4 -I https://example.com/
curl -6 -I https://example.com/

这些命令用于验证实际环境,不代表示例域名在所有网络中都会同时提供 IPv4 和 IPv6 可达性。具体结果会受到 DNS 响应、客户端配置、网络策略和目标站点状态影响。

DNS 返回 AAAA 记录,但 IPv6 连接失败,可能是什么原因?

因为 DNS 记录只是地址信息,并不承诺端到端连通性。还需要满足:

  1. 客户端网络有可用的 IPv6 配置和路由;
  2. 目标服务确实在该 IPv6 地址和相应端口上提供服务;
  3. 防火墙、安全策略和返回路径允许连接;
  4. TLS 和应用层请求本身正常。

所以,"能解析"与"能连接"是两个不同结论。不要仅凭 AAAA 查询成功,就判断 IPv6 网络已经正常。

六、什么是双栈网络?客户端如何选择 IPv4 或 IPv6?

6.1 双栈不是把 IPv4 地址转换成 IPv6 地址

双栈(Dual Stack)通常指设备或网络同时支持 IPv4 和 IPv6 协议。设备可能拥有 IPv4 地址,也拥有一个或多个 IPv6 地址,并根据目标地址、路由和应用连接策略进行通信。

它不意味着 IPv4 地址会自动转换成 IPv6 地址,也不意味着每一个服务都同时支持两种协议。

在迁移期间,双栈是一种常见部署方式:旧系统仍可使用 IPv4,新系统或具备条件的链路可以使用 IPv6。

6.2 如果 DNS 同时返回 A 和 AAAA,客户端一定先用 IPv6 吗?

不一定。客户端会综合地址排序、系统策略、网络可用性和具体连接实现来选择目标地址。

为了避免某一地址族不可用时造成长时间等待,RFC 8305 定义了 Happy Eyeballs v2 连接建立算法。它的基本思想是:对不同地址族的候选地址进行合理排序,并错开启动连接尝试;一旦有一个连接成功,就可以取消其他不再需要的尝试。

这不等于每个客户端都会同时发起所有连接,也不意味着 IPv6 永远优先。具体行为取决于操作系统、运行时、应用程序和网络配置。

6.3 IPv6 一定比 IPv4 快吗?

不能这样下结论。IPv6 与 IPv4 哪个更快,取决于具体网络路径、运营商互联、服务端部署、客户端策略、拥塞情况和其他因素。

如果某个网络的 IPv6 路径配置不完整,IPv6 连接反而可能失败或变慢;如果 IPv6 路径更直接,也可能表现更好。应该通过真实环境中的连接结果和性能数据判断,而不是只根据协议版本判断。

七、Java 后端开发中如何检查域名解析结果?

Java 程序可以通过 InetAddress 查询主机名对应的地址。下面的示例只展示如何检查当前 Java 运行环境解析到了哪些地址,不会假设结果中一定同时包含 IPv4 和 IPv6。

环境: JDK 17,无需第三方依赖。示例使用文档示例域名,实际解析结果取决于 DNS 和运行环境。

java 复制代码
import java.net.Inet6Address;
import java.net.InetAddress;

public class DnsAddressCheck {
    public static void main(String[] args) throws Exception {
        InetAddress[] addresses =
                InetAddress.getAllByName("example.com");

        for (InetAddress address : addresses) {
            String type = address instanceof Inet6Address
                    ? "IPv6"
                    : "IPv4";

            System.out.printf("%s -> %s%n",
                    type, address.getHostAddress());
        }
    }
}

这段代码的重点是:

  • InetAddress.getAllByName(...):查询当前 Java 环境可获得的主机地址列表。
  • instanceof Inet6Address:判断返回对象是否表示 IPv6 地址。
  • getHostAddress():以文本形式输出地址。

需要注意,结果会受 DNS 记录、系统解析器、JVM 缓存和运行环境影响。getAllByName() 返回地址列表,并不代表程序最终会按某个固定顺序连接,也不代表每个地址都能访问。

在真实项目中,如果出现"终端能访问、Java 程序却连接失败",应比较两者运行环境、DNS 结果、代理设置、连接策略以及目标服务的 IPv4/IPv6 监听情况,而不是直接认定为 Java 或 IPv6 协议本身有问题。

八、IPv6 常见误区

误区 1:IPv6 地址越长,就一定越安全

错误。IPv6 扩大了地址空间,并调整了协议机制,但地址长度本身不是安全防护。访问控制、防火墙策略、系统补丁、身份认证和服务配置仍然重要。

误区 2:使用 IPv6 就不需要防火墙

错误。IPv6 网络同样需要合理的入站、出站和转发策略。不能因为地址不再依赖传统 IPv4 NAT 的常见部署方式,就认为主机上的服务应该默认暴露到公网。

误区 3:IPv6 一定没有 NAT

错误。IPv6 设计并不要求像许多 IPv4 网络那样依赖地址转换,但实际部署中仍存在特定的 IPv6/IPv4 转换与互通机制。不能把"地址空间更充足"理解为"任何网络都不会使用转换技术"。

误区 4:看到 fe80:: 就能从其他电脑访问

错误。链路本地地址只在本地链路范围内有效。即使在同一台电脑上,使用链路本地地址访问时也可能需要明确指定接口范围,具体语法取决于操作系统和工具。

误区 5:AAAA 记录存在,就说明网站的 IPv6 已经部署完成

错误。AAAA 记录只说明 DNS 返回了 IPv6 地址信息。实际访问还依赖 IPv6 路由、目标端口监听、防火墙、TLS 和应用层配置。

九、本篇总结

本文需要掌握的重点:

  1. IPv6 地址长度为 128 位,通常写成 8 组十六进制字段。
  2. :: 可以压缩连续零字段,但同一个地址中只能出现一次;规范文本表示还有更具体的推荐规则。
  3. 全球单播、链路本地、唯一本地、回环、未指定、组播和任播具有不同用途。
  4. DNS 的 A 记录存储 IPv4 地址,AAAA 记录存储 IPv6 地址;DNS 解析成功不代表连接成功。
  5. 双栈表示同时支持 IPv4 和 IPv6;Happy Eyeballs 等策略可以降低某一地址族连接异常带来的等待。
  6. Java 可以通过 InetAddress 检查当前运行环境解析得到的地址,但实际连接行为还取决于运行环境和连接策略。

一句话记忆:IPv6 不只是更长的地址,还涉及地址范围、自动配置、DNS 记录和双栈连接策略。

我是程序员大海,我们下期不见不散.

参考资料

  1. RFC 8200:Internet Protocol, Version 6 (IPv6) Specification
  2. RFC 4291:IP Version 6 Addressing Architecture
  3. RFC 5952:A Recommendation for IPv6 Address Text Representation
  4. RFC 3596:DNS Extensions to Support IP Version 6(AAAA 记录)
  5. RFC 4861:Neighbor Discovery for IP version 6 (IPv6)
  6. RFC 8305:Happy Eyeballs Version 2
  7. IANA:IPv6 Global Unicast Address Space

本文中的地址示例用于说明协议概念,不代表特定服务器的实际配置或运行结果。命令与 Java 示例提供了可执行的检查方式,但本文未声称在某个实际网络中运行过它们,也未预设输出结果。

相关推荐
2401_868534781 小时前
论纯IPv6(IPv6-Only)演进与地址规划设计与实施
服务器·网络
(●—●)橘子……1 小时前
力扣 第525场周赛 练习理解
数据结构·python·学习·算法·leetcode
爱和冰阔落1 小时前
【Linux网络】UDP 服务器怎么写?从 socket、bind 到 recvfrom/sendto,手写完整回显服务器
linux·运维·服务器·网络
Rain的Java大神之路1 小时前
LeetCode 21 合并两个有序链表:一道 Easy 题,凭什么刷掉一半候选人?
java·后端·算法
w_t_y_y1 小时前
JWT(5)JWT+spring security
java·后端·spring
一只QAQ1 小时前
python语法学习
linux·python·学习
明王明王1 小时前
PVE 装 OpenWrt:不改现有网络,用单臂路由让指定虚拟机上网
网络·openwrt
2301_780789661 小时前
SSL 卸载 + WAF + 抗 D:高防 CDN 一站式解决 HTTPS 性能与安全
网络·云原生·ddos
moonsims1 小时前
AiBrainBox-UGV 通 · 感 · 算 · 控一体化地面机器人边缘智能平台 规格书
大数据·网络·人工智能·无人机