Skip to content

IPv4 与 IPv6

查看 Markdown

TCP、UDP、RUDP、HTTP/HTTPS、WebSocket/WSS 和 TLS 通过同一套 start(host, port) 接口接收 IPv4、IPv6 地址。UDP cast 也支持 IPv6 端点。

用途 IPv4 IPv6
回环监听/连接 127.0.0.1 ::1
监听所有接口 0.0.0.0 ::
HTTP Host/WebSocket authority 127.0.0.1:8080 [::1]:8080
URL http://127.0.0.1:8080/ http://[::1]:8080/

传给 start 的 IPv6 地址不加方括号,端口用单独参数传入。 HTTP 请求自行设置 Host;WebSocket 客户端构造握手地址。 域名可能解析到任一种地址族,localhost 不保证使用 IPv6。

域名与地址解析

域名传给 host,端口用单独参数传入:

arknet::tcp_client client;
if (!client.start("example.com", 9000))
    std::cerr << arknet::last_error_msg() << '\n';

HTTP 客户端可以省略端口:http_client.start("example.com") 默认使用 80, https_client.start("example.com") 默认使用 443,异步接口 async_start(host) 遵循相同规则。http_request.async_request(host, request, completion) 默认使用 80。 显式端口优先;TCP、UDP、RUDP 等通用端点仍需指定端口。 具体示例见 HTTP 客户端。

客户端使用 Asio 异步 resolver,遵循操作系统的名称解析配置,包括 DNS 和 hosts 文件。解析结果可以包含 IPv4 或 IPv6 地址。基于 TCP 的客户端在 socket 连接失败后,按解析器返回的顺序尝试其他地址,未实现 IPv4/IPv6 并行连接的 Happy Eyeballs 策略。UDP 的 connect 只设置对端地址,不验证对端是否可达; UDP 和 RUDP 不会根据对端可达性自动切换地址。

Asio 的 endpoint 保存 IP 地址和端口,不能保存域名。 arknet::to_endpoint<asio::ip::tcp::endpoint>(host, port) 同步解析并返回第一个地址, 使用前检查 arknet::get_last_error()。 UDP cast 的 async_send(host, port, data) 异步解析,并选取第一个与 socket 的 IPv4/IPv6 地址族一致的地址。

HTTPS 和 WSS 保留域名用于 TLS SNI 和证书身份校验。除非证书包含对应 IP 身份,否则不要用解析后的 IP 替代域名。连接建立后保持当前对端地址,重连时 重新解析。arknet 尚未提供选择自定义 DNS 服务器的 API。

客户端与服务端

完整的 IPv6 回显示例 在 ::1 上启动两端,检查回复后停止。构建并运行:

cmake --build build --target arknet_ipv6_echo
build/examples/arknet_ipv6_echo

TCP、UDP、 WebSocket 和 HTTP 的客户端、服务端示例 可将两端回环地址改为 ::1。HTTP 请求使用:

request.set(arknet::http::field::host, "[::1]:8080");

TLS 客户端将 IP 地址与证书的 IP subject alternative name 校验,包括完整的 IPv6 地址。只有 localhost 或 127.0.0.1 身份的证书不能验证 ::1。 身份配置见 TLS 用法。独立的 tests/certs/ipv6 证书仅用于测试。

监听策略

绑定 :: 会监听全部 IPv6 接口。是否接收 IPv4 映射连接取决于平台的 IPV6_V6ONLY 策略,单独绑定 :: 不保证双栈服务。 需要明确支持两种地址族时,可分别监听 0.0.0.0 和 ::,并将 IPv6 socket 设为只接收 IPv6。在 socket 打开后、绑定前,通过 bind_init 设置选项:

server.bind_init([&]
{
    arknet::error_code error;
    server.acceptor().set_option(asio::ip::v6_only(true), error);
    if (error) throw arknet::system_error(error);
});

应用需要接受外部流量时才监听外部接口。UDP 多播配置区分地址族,IPv6 没有 IPv4 广播的等价功能。链路本地 IPv6 地址还需要指定接口作用域。

测试与基准

独立 doctest 程序为 build/tests/arknet_ipv6_test。 两个 C++ 基准和 shell 批量工具均支持 --address-family ipv6:

build/benchmarks/arknet_loopback_benchmark --protocol udp --address-family ipv6 \
  --payload 1024 --clients 16 --window 1 --io-model shared --io-threads 1 \
  --seconds 1 --warmup 0.25
build/benchmarks/arknet_loopback_benchmark --protocol https --address-family ipv6 \
  --certs tests/certs/ipv6 --payload 1024 --clients 16 --window 1 \
  --io-model shared --io-threads 1 --seconds 1 --warmup 0.25
build/benchmarks/arknet_coroutine_benchmark --protocol tcp --execution coroutine \
  --address-family ipv6 --payload 1024 --clients 16 --window 16 \
  --io-model shared --io-threads 4 --seconds 1 --warmup 0.25

现有性能矩阵使用 IPv4 回环。::1 验证不代表跨主机吞吐量、IPv4/IPv6 性能一致、 多播可用性或所有平台的双栈行为。

Navigation

Type to search…

↑↓ navigate↵ selectEsc close