我已经看到并阅读了很多类似的问题,以及相应的维基百科文章(NAT traversal ,STUN,TURN, TCP 打洞),但是大量的信息并不能真正帮助我解决非常简单的问题:
我正在编写一个 P2P 应用程序,并且我希望 NAT 后面的应用程序的两个用户能够相互连接。连接必须可靠(与 TCP 的可靠性相当),所以我不能只切换到 UDP。该解决方案应该适用于当今的通用系统,无需重新配置。如果有帮助,该解决方案可能涉及可连接的第 3 方,只要它不必代理整个数据(例如,获取对等方的外部 (WAN) IP 地址)。
据我所知,我唯一的选择是使用“可靠的UDP”库+ UDP打洞。有这个的(C/C++)库吗?我在 enet -do-you-use-when-you-need-reliable-udp/107684#107684">相关问题,但它只处理解决方案的前半部分。
还要别的吗?我看过的东西:
- Teredo 隧道 - 需要操作系统和/或用户的支持配置
- UPnP 端口转发 - UPnP 不在任何地方存在/启用
- TCP 打洞 似乎是实验性的,仅在某些情况下有效
- SCTP 的支持程度甚至低于 IPv6。 SCTP over UDP 只是一种奇特可靠的 UDP(见上文)
- RUDP - 几乎没有主流
- 支持我能理解 STUN、STUNT、TURN 和 ICE,但它们都帮不了我。
I've seen and read a lot of similar questions, and the corresponding Wikipedia articles (NAT traversal, STUN, TURN, TCP hole punching), but the overwhelming amount of information doesn't really help me with my very simple problem:
I'm writing a P2P application, and I want two users of my application behind NAT to be able to connect to each other. The connection must be reliable (comparable to TCP's reliability) so I can't just switch to UDP. The solution should work on today's common systems without reconfiguration. If it helps, the solution may involve a connectible 3rd-party, as long as it doesn't have to proxy the entire data (for example, to get the peers' external (WAN) IP addresses).
As far as I know, my only option is to use a "reliable UDP" library + UDP hole punching. Is there a (C/C++) library for this? I found enet in a related question, but it only takes care of the first half of the solution.
Anything else? Things I've looked at:
- Teredo tunnelling - requires support from the operating system and/or user configuration
- UPnP port forwarding - UPnP isn't present/enabled everywhere
- TCP hole punching seems to be experimental and only work in certain circumstances
- SCTP is even less supported than IPv6. SCTP over UDP is just fancy reliable UDP (see above)
- RUDP - nearly no mainstream support
- From what I could understand of STUN, STUNT, TURN and ICE, none of them would help me here.
发布评论
评论(2)
ICE 收集要连接的候选 IP/端口目标的列表。每个对等点都会收集这些信息,然后按顺序对每个候选点运行连接检查,直到检查通过或检查失败。
当爱丽丝尝试连接到鲍勃时,她以某种方式获得了可能的方式列表(由鲍勃确定),她可以连接到鲍勃。 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 的架构,但它是动态设置的。
ICE collects a list of candidate IP/port targets to which to connect. Each peer collects these, and then each runs a connectivity check on each of the candidates in order, until either a check passes or a check fails.
When Alice tries to connect to Bob, she somehow gets a list of possible ways - determined by Bob - she may connect to Bob. ICE calls these candidates. Bob might say, for example: "my local socket's 192.168.1.1:1024/udp, my external NAT binding (found through STUN) is 196.25.1.1:4454/udp, and you can invoke a media relay (a middlebox) at 1.2.3.4:6675/udp". Bob puts that in an SDP packet (a description of these various candidates), and sends that to Alice in some way. (In SIP, the original use case for ICE, the SDP's carried in a SIP INVITE/200/ACK exchange, setting up a SIP session.)
ICE is pluggable, and you can configure the precise nature/number of candidates. You could try a direct link, followed by asking a STUN server for a binding (this punches a hole in your NAT, and tells you the external IP/port of that hole, which you put into your session description), and falling back on asking a TURN server to relay your data.
One downside to ICE is that your peers exchange SDP descriptions, which you may or may not like. Another is that TCP support's still in draft form, which may or may not be a problem for you. [UPDATE: ICE is now officially RFC 6544.]
Games often use UDP, because old data is useless. (This is why RTP usually runs over UDP.) Some P2P applications often use middleboxes or networks of middleboxes.
IRC uses a network of middleboxes: IRC servers form networks, and clients connect to a near server. Messages from one client to another may travel through the network of servers.
Failing all that, you could take a look at BitTorrent's architecture and see how they handle the NAT problem. As CodeShadow points out in the comments below, BitTorrent relies on reachable peers in the network: in a sense some peers form a network of middleboxes. If those middleboxes could act as relays, you'd have an IRC-like architecture, but one that's set up dynamically.
我推荐 libjingle,因为一些主要的视频游戏公司大量使用它依赖于P2P网络通信。 (您听说过 Steam 吗?Vavle 还使用 libjingle ,请参阅“页面中的点对点网络”会话: https://partner.steamgames.com/documentation/api )
但是,始终有效的解决方案将使用中继服务器。由于没有通过 NAT 的“标准”方法,因此如果必须始终在任何对等方之间建立连接,您应该将此中继服务器选项作为后备策略。
I recommend libjingle as it is used by some major video game companies which heavily relies on P2P network communication. (Have you heard about Steam? Vavle also uses libjingle , see the "Peer-to-peer networking" session in the page: https://partner.steamgames.com/documentation/api)
However, the always-work-solution would be using a relay server. Since there is no "standard" way to go through NAT, you should have this relay server option as a fall-back strategy if a connection has to be always established between any peers.