10

我正在开发一个连接到用户指定的公共服务器的网络客户端程序。如果用户给我一个主机名来连接,该主机名同时具有 IPv4 和 IPv6 地址(通常是一个同时具有AAAAA记录的 DNS 名称),我不确定我应该如何决定应该连接到哪个地址。

问题是机器同时支持 IPv4 和 IPv6 是很常见的,但只能通过 IPv4 进行全球连接。最常见的情况是仅配置 IPv6 链路本地地址。目前我能想到的最好的选择是:

  1. 首先尝试 IPv6 地址 - 如果连接失败,请尝试 IPv4 地址;或者
  2. 只需让用户将其指定为配置设置(“prefer_ipv6”与“prefer_ipv4”)。

我可以看到选项 1 的问题是连接可能不会立即失败 - 可能需要很长时间才能超时。

4

5 回答 5

9

请尝试 IPv6。在绝大多数安装中,如果由于某种原因无法成功,尝试创建 IPv6 连接将立即失败:

  • 如果系统不支持 IPv6 套接字,创建套接字将失败
  • 如果系统确实支持 IPv6,并且配置了链路本地地址,则不会有任何用于全局 IPv6 地址的路由表条目。同样,本地内核将报告失败而不发送任何数据包。
  • 如果系统确实有一个全局 IP 地址,但缺少路由所需的某些链接,则源收到 ICMPv6 错误消息,指示无法到达目标;同样,如果目的地有一个 IPv6 地址,但服务没有监听它。

当然,在某些情况下,事情可能会中断,例如,如果配置了全局(或隧道)地址,并且某些东西会错误地过滤掉 ICMPv6 错误消息。您不必担心这种情况 - IPv4 连接可能会以某种方式中断。

当然,您是否真的需要先尝试 IPv6 地址是有争议的——您不妨尝试它们。通常,您应该按照从 getaddrinfo 返回的顺序尝试地址。今天,系统支持配置选项,让管理员可以决定从 getaddrinfo 返回地址的顺序。

于 2009-08-29T18:57:55.747 回答
5

在提出这个问题之后,IETF 已通过RFC6555(又名Happy Eyeballs)提出了对这个问题的回答。

相关的一点是客户端和服务器可能都具有 IPv4 和 IPv6,但它们之间的跃点可能没有,因此无法可靠地预测哪条路径将起作用。

于 2013-04-23T00:50:57.663 回答
2

您应该让系统范围的配置来决定,这要归功于getaddrinfo(). 就像Java一样。要求每个应用程序尝试满足每个可能的 IPv6(错误)配置确实是不可扩展的!在配置错误的情况下,如果所有或没有应用程序中断,用户会更加直观。

另一方面,您想尝试大量记录烦人的延迟和超时,以便用户可以快速确定应该归咎于什么。就像理想情况下的所有其他延迟一样,包括(非常常见的)DNS 超时。

于 2010-11-10T11:48:10.213 回答
1

这个谈话有解决办法。总结;

  • 有时,DNS 查找或与已解析地址的后续连接存在问题
  • 您不想在连接到 IPv4 地址之前等待连接到 IPv6 地址超时,反之亦然
  • 您不想在查找 A 记录之前等待查找 AAAA 记录超时,反之亦然
  • 您不希望在等待 AAAA 和 A 记录之前停止,然后再尝试连接您首先返回的任何记录。

解决方案是同时独立地查找 AAAA 和 A 记录,并独立连接到已解析的地址。首先使用任何连接成功。


执行此操作的最简单方法是允许网络 API 使用按名称连接网络 API 为您执行此操作。例如,在 Java 中:

InetSocketAddress socketAddress = new InetSocketAddress("www.example.com", 80);
SocketChannel channel = SocketChannel.open(socketAddress);
channel.write(buffer);

幻灯片说明在这一点上说:

在这里,我们从主机和端口创建了一个名为 InetSocketAddress 的不透明对象,然后当我们打开该 SocketChannel 时,它可以在幕后完成,做任何必要的事情,而应用程序永远不会看到 IP 地址。

Windows 也有按名称连接的 API。我这里没有代码片段。

现在,我并不是说这些 API 的所有实现都必须在今天做正确的事情,但如果应用程序正在使用这些 API,那么随着时间的推移,这些实现可以得到改进。

与 getaddrinfo() 和类似 API 的不同之处在于,它们从根本上无法随着时间的推移而改进。API 的定义是他们返回给你一个完整的地址列表,所以他们必须等到他们有完整的列表才能给你。getaddrinfo 无法返回部分列表,然后再给您更多。

于 2013-04-22T22:29:01.697 回答
-2

一些想法:

  1. 允许用户在每个站点的基础上指定首选项。
  2. 首先尝试 IPv4。
  3. 在第一次连接时并行尝试 IPv6。
  4. 在后续连接中,如果之前连接成功,则使用 IPv6。

我说首先尝试 IPv4,因为这是更好地建立和测试的协议。

于 2009-08-29T06:01:56.483 回答