草庐IT

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

coder 2023-09-17 原文

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

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

A--[Router1]--S--[Router2]--B

  • A连接到S并授权
  • B连接到S并授权
  • A想给B发一个文件
  • A 向 S 请求与 B 的连接
  • S [这很神奇吗] 并且 A 现在与 B 有联系
  • A开始发送文件
  • S 下降(或至少文件传输绕过)
  • A和B之间仍然存在联系
  • A继续发送文件给B

我的问题:

  1. 这可能吗?
  2. 如何做到这一点?
  3. 遇到过可以做到这一点的示例项目吗?

我找到了 WCF / WPF Chat Application , 但它原来是一个代理。

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

最佳答案

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

这是来自 UDP Hole Punching 的算法摘要页面。

Let A and B be the two hosts, each in its own private network; N1 and N2 are the two NAT devices with globally reachable IP addresses P1 and P2 respectively; S is a public server with a well-known globally reachable IP address.

  1. A and B each begin a UDP conversation with S; the NAT devices N1 and N2 create UDP translation states and assign temporary external port numbers X and Y
  2. S examines the UDP packets to get the source port used by N1 and N2 (the external NAT ports X and Y)
  3. S passes P1:X to B and P2:Y to A
  4. A sends a packet to P2:Y and B sends a packet to P1:X using the same source port as the conversation with S thus "punching" a hole in the NAT towards the other host
  5. If either host receives a packet, the hole punching is successful and both hosts can communicate.

If both hosts have Restricted cone NATs or Symmetric NATs, the external NAT ports will differ from those used with S. On some routers, the external ports are picked sequentially making it possible to establish a conversation through guessing nearby ports.

它是否会工作在很大程度上取决于端点的 NAT 路由器的行为方式,很可能您的很大一部分使用会配对,并且两者都有不“打洞友好”的路由器。

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

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

关于c# - 当两个客户端都在 NAT 后面时如何创建 P2P 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18519818/

有关c# - 当两个客户端都在 NAT 后面时如何创建 P2P 连接的更多相关文章

  1. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  2. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  3. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

    我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

  4. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  5. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  6. ruby - 具有两个参数的 block - 2

    我从用户Hirolau那里找到了这段代码:defsum_to_n?(a,n)a.combination(2).find{|x,y|x+y==n}enda=[1,2,3,4,5]sum_to_n?(a,9)#=>[4,5]sum_to_n?(a,11)#=>nil我如何知道何时可以将两个参数发送到预定义方法(如find)?我不清楚,因为有时它不起作用。这是重新定义的东西吗? 最佳答案 如果您查看Enumerable#find的文档,您会发现它只接受一个block参数。您可以将它发送两次的原因是因为Ruby可以方便地让您根据它的“并行赋

  7. arrays - 如何在下面的示例中将两个值数组分组为 n 个值数组? - 2

    我已经有很多两个值数组,例如下面的例子ary=[[1,2],[2,3],[1,3],[4,5],[5,6],[4,7],[7,8],[4,8]]我想把它们分组到[1,2,3],[4,5],[5,6],[4,7,8]因为意思是1和2有关系,2和3有关系,1和3有关系,所以1,2,3都有关系我如何通过ruby​​库或任何算法来做到这一点? 最佳答案 这是基本Bron–Kerboschalgorithm的Ruby实现:classGraphdefinitialize(edges)@edges=edgesenddeffind_maximum_

  8. ruby - 尝试比较两个文本文件,并根据信息创建第三个 - 2

    我有两个文本文件,master.txt和926.txt。如果926.txt中有一行不在master.txt中,我想写入一个新文件notinbook.txt。我写了我能想到的最好的东西,但考虑到我是一个糟糕的/新手程序员,它失败了。这是我的东西g=File.new("notinbook.txt","w")File.open("926.txt","r")do|f|while(line=f.gets)x=line.chompifFile.open("master.txt","w")do|h|endwhile(line=h.gets)ifline.chomp!=xputslineendende

  9. ruby - 在两个 ActiveRecord 类之间合并/复制属性的好方法? - 2

    之前有人问过这个问题,我发现了以下clip关于如何一次设置一个类对象的所有属性,但由于批量分配保护,这在Rails中是不可能的。(例如,您不能Object.attributes={})有没有一种很好的方法可以将一个类的属性合并到另一个类中?object1.attributes=object2.attributes.inject({}){|h,(k,v)|h[k]=vifObjectModel.column_names.include?(k);h}谢谢。 最佳答案 利用assign_attributes使用:without_prote

  10. ruby-on-rails - ruby 中两个哈希之间的变化 - 2

    我有两个具有以下格式的哈希mydetails[x['Id']]=x['Amount']这将包含如下数据hash1={"A"=>"0","B"=>"1","C"=>"0","F"=>"1"}hash2={"A"=>"0","B"=>"3","C"=>"0","E"=>"1"}我期待这样的输出:Differencesinhash:"B,F,E"非常感谢任何帮助。 最佳答案 这个解决方案可能更容易理解:(hash1.keys|hash2.keys).select{|key|hash1[key]!=hash2[key]}Array#|返回2

随机推荐