返回文章列表

文章

iroh在NAT环境下建立P2P连接的完整流程

目录
  1. 一、参与角色
  2. 二、阶段 0:节点上线
  3. 三、阶段 1:生成 ticket
  4. 四、阶段 2:ticket 的传递
  5. 五、阶段 3:B 使用 ticket 连接 A
  6. 六、阶段 4:尝试 NAT 穿透(UDP 打洞)
  7. 成功
  8. 失败(对称 NAT 等)
  9. 七、阶段 5:直连 / Relay fallback 数据传输
  10. 八、直觉类比
  11. 九、整合一句话总结

一、参与角色#

角色描述
AProvider / Sender,提供服务的一方
BReceiver / Client,发起连接的一方
RRelay / 信令中继,公网可达,帮助节点互相发现和穿透 NAT

所有节点都是 iroh Endpoint 的实例,Relay 是特殊的公网 Endpoint。


二、阶段 0:节点上线#

  1. Endpoint 创建
let endpoint = Endpoint::builder().bind().await?;

  1. Endpoint 内部动作
    • 监听本地端口(UDP / QUIC)
    • 向 Relay 建立出站连接(NAT 允许)
    • Relay 记录 NodeId 与可达性信息

✅ NAT 不会阻止出站连接,因此注册总是成功的


三、阶段 1:生成 ticket#

  • ticket 的作用:告诉对方节点如何找到自己
  • ticket 内容
    • NodeId(身份标识)
    • 可选的直连地址
    • Relay 提示
    • 身份认证信息

🔑 ticket 并非一次性,它描述的是 Endpoint 的可达性和身份,只要 Endpoint 活着,就可以多次使用。


四、阶段 2:ticket 的传递#

  • 方式(不依赖 iroh 网络层):
    • 二维码、IM、HTTP API、剪贴板、邮件等
  • 目的:让 B 得到 A 的 NodeId 与 Relay 信息

这是信令层行为,不涉及 P2P 数据传输


五、阶段 3:B 使用 ticket 连接 A#

let conn = endpoint.connect(ticket).await?;

Endpoint 内部执行:

  1. 从 ticket 获取 A 的 NodeId 和 Relay 地址
  2. 先连接 Relay(出站连接)
  3. 向 Relay 说:“我想找 NodeId = A”
  4. Relay 交换 A ↔ B 的可达信息

✅ 通过 Relay,B 能找到 A 的网络位置,即使在 NAT 后


六、阶段 4:尝试 NAT 穿透(UDP 打洞)#

  1. 双方同时向对方地址发送 UDP 包
  2. NAT 会为临时端口打开映射
  3. 数据包在 NAT 中相遇 → 建立直连

成功#

  • 建立 P2P 直连
  • Relay 退出数据路径

失败(对称 NAT 等)#

  • Relay 继续转发数据
  • 应用层无感知

七、阶段 5:直连 / Relay fallback 数据传输#

  • 直连成功:低延迟、高性能 P2P
  • 直连失败:Relay 做中继,保证通信可靠性
  • Endpoint 层面:统一管理连接,应用无需关心底层路径选择

八、直觉类比#

  • Relay = 社交中介
    • 你想联系朋友,但不知道他在哪
    • 先通过中介介绍
    • 中介帮助尝试直连
    • 直连失败 → 中介继续转发消息
  • ticket = 名片
    • 告诉别人你的身份和可达性
  • Endpoint = 网络化身份
    • 包含身份、可达性、连接管理
    • 自动选择直连或 Relay

九、整合一句话总结#

iroh 的 P2P 连接流程:ticket 提供身份信息 → Relay 协助发现 → 双方尝试 NAT 打洞 → 直连成功则 P2P,失败则 Relay fallback → Endpoint 管理整个过程。