c# - 没有中央服务器的 P2P 握手

标签 c# .net networking network-programming p2p

我编写了一个客户端-服务器应用程序,旨在通过局域网交换文件(以及其他内容)。在服务器模式下,应用程序监听具有特定标识 header 的 TCP 连接。在客户端模式下,它会尝试与用户提供的 IP 地址建立 TCP 连接。

我现在需要调整此应用程序以在 Internet 上工作。在没有太多网络编程知识的情况下,我不确定如何在没有某种中央服务器(用于宣布存在等)的情况下实现这一点。这不是一个选项。

假设我的应用程序在家庭网络后面的机器上以服务器模式运行。您(读者)的应用程序处于客户端模式,我们需要连接。我们都没有静态 IP 地址。客户端有没有办法到达服务器?服务器和客户端都可以找出它们的公共(public) IP 地址,但除此之外,我不确定该怎么做。

如有任何指导,我们将不胜感激。

编辑:根据答案,需要进行一些澄清。我的问题不是关于发现。客户端和服务器都可以查询它们的公共(public)地址,用户可以通过其他媒介交换这些 IP。问题是,一旦对方的 IP 已知但双方都位于没有适当端口转发的网络后面,如何建立连接。例如,我的应用通过 TCP 使用端口 51200 作为默认值。

最佳答案

我了解到,由于涉及 NAT 类型的某些可能组合,UDP 打洞技术在 2 个对等点之间获得真正的直接连接是不完美的。这意味着 UDP 打洞单独并不总是有效。

声称 100% 可操作性的方法是,在无法进行 p2p 连接的情况下,使用中继服务器。发现真正的 p2p 连接是否可能的过程已经由 ICE、TURN 和 STUN 标准化。我所知道的是,使用ICE/TURN/STUN似乎是颠覆NAT问题的标准化策略。它可以在可用时促进真正的 p2p 连接,并在必要时提供中继服务。

注意:我在此答案中使用术语 p2p 来区分 2 个端点之间的真正直接连接,不要与覆盖网络等混淆。

高级用户:通过引入更复杂的策略来配合对称NAT行为,例如端口预测等,可以获得更直接的p2p连接。但是实现这些方法的库是昂贵的,对于 DIY 工作来说似乎太难了。

我没有详细解释不同类型的 NAT 连接可能性。您将需要研究 NAT 类型以及它们与 UDP 打洞的关系。那里有 RFC,我会尝试用链接更新我的答案。但重点是,您可以通过重新关注 TURN/STUN/ICE 的实现、了解它们的实现方式以及如何使用它们的标准化行为来避免大量此类学习。

可能的解决方案

  • PJSIP - 包含用于 C/C++ 的独立高级 NAT 遍历库,还具有其他语言的绑定(bind)。如果您只需要 NAT Traversal 库子组件,请参阅 PJNATH
  • LibJingle - 基于 XMPP 构建的 P2P(点对点)和 RTC(实时通信)堆栈。请注意,许多 LibJingle 实现无法与实际的 XMPP Jingle 规范和附属规范互操作。

这些可能会给程序增加相当大的复杂性,这就是为什么有必要自己实现一些机制。

文件

互联网工作组

RFC

微软

注意事项

我听说最终迁移到 IPv6 可能会解决 NAT 穿越问题,但是 [probably not] .有人可以启发这个话题。无论哪种方式,从我没有经验的角度来看,向 IPv6 的进展似乎都很缓慢,我不会指望它作为解决方案。

关于c# - 没有中央服务器的 P2P 握手,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23810734/

相关文章:

ios - iOS 后台模式下本地主机没有响应

c# - 创建松散耦合/可扩展的软件架构

c# - 将用户在文本框中输入的 URL 转换为 URI 格式

c# - 经常调用的方法中的新临时变量

c# - 为什么 IProgress<T> Report(T) 方法会阻塞 UI 线程?

java - 通过 Web 服务将文件从 java 发送到 .net

android - 如果设备连接到路由器,如何检查互联网连接可用性?

c# - 打破内部 foreach 循环并继续外部 foreach 循环

c# - 在 .net 中以编程方式突出显示 PDF - 是否有任何 API 和库来生成偏移文件或是否有更好的方法?

c++ - close() 和 close socket() 可以互换吗?