可靠的网络连接的实用NAT穿透

14
我看过很多类似的问题和对应的维基百科文章(NAT遍历, STUN, TURN, TCP穿透),但是这些海量的信息并没有真正帮助我解决我的非常简单的问题:
我正在编写一个 P2P 应用程序,并且我希望在 NAT 后面使用我的应用程序的两个用户能够相互连接。连接必须是可靠的(与 TCP 的可靠性相当),因此我不能只切换到 UDP。解决方案应该在今天的常见系统上工作,不需要重新配置。如果有帮助的话,解决方案可能涉及可连接的第三方,只要它不必代理整个数据(例如获取同行的外部(WAN)IP地址)。
据我所知,我唯一的选择是使用“可靠UDP”库+UDP打洞。是否有这方面的(C/C++)库?我在一个相关问题中找到了enet,但它只处理解决方案的前半部分。
还有其他什么吗?我看过的东西:
  1. Teredo隧道 - 需要操作系统和/或用户配置的支持
  2. UPnP端口转发 - UPnP并非在所有地方都可用/启用
  3. TCP穿透似乎是实验性的,只在某些情况下工作
  4. SCTP的支持甚至比IPv6还少。 SCTP over UDP只是高级可靠的UDP(见上文)
  5. RUDP - 几乎没有主流支持
  6. 根据我对STUN、STUNT、TURN和ICE的了解,它们都无法帮助我。

2
你发现了一个简单的问题,但它其实并不简单——NAT穿透是很困难的。ICE为什么不太合适?是因为它使用了SDP吗?还是其他原因? - Frank Shearar
也许是因为我无法理解庞大的术语堆积,所以我不知道 ICE 怎么会对我有帮助?根据我的理解,简单来说,ICE 只是确定它是否可以建立直接连接,如果无法建立,则使用中间服务器隧道传输数据。 - Vladimir Panteleev
4
另外,我有点不相信还没有人解决这个问题。我的意思是,这一定非常普遍!主要出现在视频游戏中(有些可以处理不可靠的连接,但并非全部)。难道每个人都要编写自己的“可靠UDP”协议吗? - Vladimir Panteleev
2个回答

6

ICE收集候选IP/端口目标列表以连接。每个对等方都会收集这些,然后按顺序对每个候选者进行连接性检查,直到检查通过或失败。

当Alice尝试连接Bob时,她以某种方式获取了可能的连接方式列表 - 由Bob确定。 ICE将其称为候选项。例如,Bob可能会说:“我的本地套接字是192.168.1.1:1024 / udp,我的外部NAT绑定(通过STUN找到)是196.25.1.1:4454 / udp,您可以在1.2.3.4上调用媒体中继(中间盒):6675 / udp”。 Bob将其放在SDP数据包中(这些各种候选者的描述),并以某种方式将其发送给Alice。(在SIP中,ICE的最初用例,SDP在SIP INVITE / 200 / ACK交换中传递,设置SIP会话。)

ICE是可插拔的,您可以配置候选者的具体性质/数量。您可以尝试直接链接,然后请求一个STUN服务器进行绑定(这会在您的NAT中打洞,并告诉您该洞的外部IP /端口,您将其放入会话描述中),并回退到请求TURN服务器来中继您的数据。
ICE的一个缺点是您的对等方交换SDP描述,这可能或可能不会让您满意。另一个是TCP支持仍处于草案形式,这可能或可能不会成为问题。[更新:ICE现已正式成为RFC 6544。]
游戏通常使用UDP协议,因为旧数据没有用处。(这就是为什么RTP通常在UDP上运行的原因。)一些P2P应用程序经常使用中间盒或中间盒网络。
IRC使用了一个中间盒网络:IRC服务器形成网络,客户端连接到附近的服务器。从一个客户端到另一个客户端的信息可能通过服务器网络传输。
如果所有这些都失败了,您可以查看BitTorrent的架构,看看它们如何处理NAT问题。正如CodeShadow在下面的评论中指出的那样,BitTorrent依赖于网络中可达的对等体:在某种意义上,一些对等体形成了一个中间盒网络。如果这些中间盒可以充当中继,您将拥有类似IRC的架构,但这是动态设置的。

1
啊...抱歉,但正如我所提到的,我对这个术语不是很了解,而且我所理解的也没有什么帮助。什么是“会话描述”,谁是候选人,为什么我需要多个IP/端口目标,如果我的问题是在两个方之间建立连接,我们为什么要谈论多个对等体? STUN不是依赖于NAT网络上存在的STUN服务器吗?SDP与在两台计算机之间建立单个可靠连接有什么关系?感谢你详细的答复,但我希望你能理解我的沮丧:( - Vladimir Panteleev
1
此外,BitTorrent 简单地使用 TCP,并依赖于至少有一些人可连接。NAT 后面的对等端对彼此无法连接,但仅限于此。我认为其他主要 P2P 网络(如 eMule 等)也是如此。这仍然允许 P2P 网络继续工作,但对于我的情况则不能这样说,因为连通性是设计的强制要求。 - Vladimir Panteleev
不用在意我上面关于 STUN 的说法,我又做了些阅读,发现它只是一种已经很成熟的 UDP 穿透程序(还可以收集网络的额外信息)。 - Vladimir Panteleev
1
感谢您澄清术语,不幸的是,我并没有更接近解决我的问题(因为我已经在问题中建议了UDP打洞,并提到中继数据不是一个选项)。我会接受您的答案作为“否,没有比问题中列举的更好的解决方案”的确认。谢谢。 - Vladimir Panteleev

3
我推荐使用libjingle,因为一些主要的视频游戏公司严重依赖于P2P网络通信。 (你听说过Steam吗?Vavle也使用libjingle,请参见页面中的“点对点网络”会话:https://partner.steamgames.com/documentation/api)然而,始终可行的解决方案是使用中继服务器。由于没有“标准”的穿越NAT的方法,如果必须在任何对等体之间始终建立连接,则应将此中继服务器选项作为备用策略。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接