当两个客户端都在NAT后面时如何创建P2P连接

And*_*Gis 4 .net c# tcp

是否可以在两个位于不同NAT后面的客户端之间建立直接连接?当然,我意识到在某种程度上,具有公共IP的服务器将是必不可少的,但我不希望它成为代理.看一下以下场景:

  • 我不想与配置网络设备有任何关系.我只是想在代码中做到这一点.
  • 我不希望服务器参与文件传输过程(出于性能原因)
  • 我们有:客户端A,客户端B和服务器S,它看起来有点像这样:

A - [路由器1] - S - [路由器2] - 乙

  • A连接到S并授权
  • B连接到S并授权
  • A想要将文件发送给B
  • A要求S连接到B
  • S [这里有魔力],A现在与B有联系
  • A开始发送文件
  • S下降(或至少文件传输绕过)
  • A和B之间仍然存在联系
  • A继续将文件发送到B

我的问题:

  1. 那可能吗?
  2. 这该怎么做?
  3. 遇到过可以做到这一点的示例项目?

我找到了WCF/WPF聊天应用程序,但结果却是一个代理.

我还发现了一些建议使用UPnP和NAT Traversal的帖子,但没有人直接回答我的第一个问题所以我没有深入研究它.

Sco*_*ain 6

您正在寻找"神奇部分"的术语称为NAT Hole Punching.不幸的是,这个主题有点过于宽泛,无法在此完全解释如何实现它,但现在知道正确的术语至少应该能够让你开始寻找正确的教程.

以下是UDP Hole Punching页面中的算法摘要.

让A和B成为两个主机,每个主机都在自己的专用网络中; N1和N2是两个NAT设备,分别具有全局可达的IP地址P1和P2; S是具有众所周知的全局可达IP地址的公共服务器.

  1. A和B各自开始与S的UDP会话; NAT设备N1和N2创建UDP转换状态并分配临时外部端口号X和Y.
  2. S检查UDP数据包以获取N1和N2使用的源端口(外部NAT端口X和Y)
  3. S将P1:X传递给B,将P2:Y传递给A.
  4. A向P2发送数据包:Y和B使用与S对话相同的源端口向P1:X发送数据包,从而在NAT中向另一主机"打孔"一个洞
  5. 如果任一主机收到数据包,则打孔成功并且两个主机都可以通信.

如果两个主机都具有受限锥形NAT对称NAT,则外部NAT端口将与S使用的端口不同.在某些路由器上,外部端口将按顺序拾取,从而可以通过猜测附近的端口来建立会话.

它是否能够正常工作在很大程度上取决于端点的NAT路由器的行为方式,很可能您的大部分用途都将配对,并且两者都具有不"打孔友好"的路由器.

在你的情况下,我会让我的软件按顺序尝试这些步骤.

  1. 检查一下我们是否可以连接(用户手动端口转发)
  2. 使用UPnP并打开一个端口
  3. 使用公共服务器进行某种形式的打孔
  4. 使用另一个将端口打开作为数据代理的对等体(超级节点).
  5. 使用我托管的服务器作为代理来转发数据.