Happy Eyeballs 是什么?
Happy Eyeballs(也称 Fast Fallback)是一套 在双栈网络(同时有 IPv6 与 IPv4)中尽量缩短首包延迟、改善用户体验的连接竞速算法。
RFC 6555 (2012) 首次提出;
RFC 8305 (2018) 将其升级为 Happy Eyeballs v2 并取代 6555,细化了 DNS 解析、连接并发与计时规则。(datatracker.ietf.org, datatracker.ietf.org)
1 背景与动机
现实网络里常出现 “IPv6 通了但质量差 / IPv6 被运营商屏蔽” 等问题。
传统客户端按 IPv6→IPv4 顺序尝试连接时,如果 IPv6 不可达,会先卡 10 ~ 30 s 超时,再回退到 IPv4 → 明显拖慢页面或 API 首开时间。
为了让 双栈用户 ≈ IPv4 单栈用户 的速度体验不受 IPv6 瑕疵影响,就需要一种智能、快速的并行尝试策略——这就是 Happy Eyeballs。
2 核心思想(v2 摘要)
| 步骤 | 说明 |
|---|---|
| ① 收集地址 | 对目标主机先做 AAAA+A 查询 → 获得 IPv6 与 IPv4 列表。 |
| ② 交错排序 | 以 IPv6, IPv4, IPv6, IPv4 … 方式交错,避免一次只尝试同族地址导致长阻塞。 |
| ③ 渐进并发拨号 | 对首地址立即 connect();等待 250 ms(RFC 8305 推荐) 后对下一地址发起第二条连接;依次递进,直至某条连接 ready。 |
| ④ 选定胜者 | 第一条进入 ESTABLISHED(或 TLS 完成)的连接即被采用;其它尝试全部 cancel()。 |
| ⑤ 记忆优化(可选) | 统计哪种族群成功率更高,下次先排优胜族群,减少不必要并发。 |
RFC 8305 还扩展到:
• 自带多 DNS 服务器场景的查询竞争
• 多端口 / 多协议(TCP, UDP, QUIC)并发
• 对移动网络切换的地址集动态更新
3 为什么叫 “Happy Eyeballs”?
IETF 文档把终端用户比喻成 eyeballs。算法通过让浏览器 / App “看见” 页面更快,使用户(眼球)“happy”。(en.wikipedia.org)
4 苹果生态里的实现现状
| API / 组件 | 是否自带 Happy Eyeballs | 备注 |
|---|---|---|
| CFNetwork / NSURLSession | ✔︎ | iOS 5 起引入 v1,iOS 11 + 升级为 v2 |
Network.framework (NWConnection) |
✔︎ | 底层已实现;App 无需额外处理 |
| getaddrinfo + 自行 connect | ✗ | 需要自己在应用层复刻算法 |
因此:**你只要用系统连接栈,早已自动享受 Happy Eyeballs;**只有在手写拨号器(自建 QUIC / Raw TCP)或为了测 IP 而逐一测试时,才需自己实现竞速逻辑。
5 自定义实现简易伪代码(Swift Concurrency)
func happyConnect(ips: [String], port: UInt16) async throws -> Socket {
let delay: UInt64 = 250_000_000 // 250 ms
var tasks: [Task<Socket, Error>] = []
for (index, ip) in ips.enumerated() {
let task = Task.detached {
try Socket.connect(ip, port: port) }
tasks.append(task)
if index == 0 {
continue }
try await Task.sleep(nanoseconds: delay)
}
do {
let winner = try await withTaskGroup(of: Socket.self) {
group -> Socket in
for t in tasks {
group.addTask {
try await t.value } }
let socket = try await group.next()!
group.cancelAll() // 其他并行尝试全部放弃
return socket
}
return winner
} catch {
throw error // 全部失败再抛
}
}
关键点: 交错地址顺序 + 渐进并发 + 及时取消。
6 调优与陷阱
| 问题 | 建议 |
|---|---|
| 并发过多占端口 / 电量 | 最多同时保持 2 ~ 3 条尝试足矣(RFC 8305 §4.2) |
| 移动网络切换 | 监听 NWPathMonitor,切网后重新解析 & 重新跑竞速 |
| TLS 0-RTT / QUIC | 竞速结束后再发应用层首包,避免对失效流量浪费数据 |
| 日志指标 | 埋点记录 “赢得竞速的地址族 + RTT” 评估网络质量 |
7 结语
Happy Eyeballs 通过 “IPv6 优先但绝不错过 IPv4” 的并发竞速,让终端在复杂双栈网络里依旧秒开连接,是现代浏览器和 iOS 网络栈的标配。
如果你只是用
NSURLSession,无需操心;如果你要自己做智能选路 / 测速,请把 RFC 8305 的节奏照搬,别让用户的眼球再“哭泣”。
参考
RFC 8305 — Happy Eyeballs v2 (datatracker.ietf.org)
RFC 6555 — Happy Eyeballs: Success with Dual-Stack Hosts (datatracker.ietf.org)
Wikipedia:Happy Eyeballs 概述与历史 (en.wikipedia.org)





















暂无评论内容