这里有不同的解决方案,但大多数都不是微不足道的,你必须做一些阅读,你需要某种后备。
UPnP/IGD 是最简单的。如果您的路由器支持它,并且配置为允许它,并且您知道如何编写低级网络代码或老式 SOAP Web 服务代码,您可以要求路由器为您分配一个端口。如果它响应成功,请开始使用该端口,您基本上就完成了。
如果您可以为所有用户运行具有公共地址的(非常低带宽的)服务器,Hole punching 可能会解决问题。
想一想 NAT 背后的客户端如何与公共服务器通信。您向某个 IP 和端口发出请求,但服务器看到的是您的路由器 IP,而不是您的 IP(这是一件好事,因为您的 IP 不可访问)。当它回复时,您的路由器必须知道将其转发给您——它只需记住您是刚刚向该服务器发送请求的 NAT 客户端。
如果您不是与公共服务器通信,而是与他自己的独立 NAT 后面的其他对等点通信,该怎么办?好吧,您的路由器不知道其中的区别;只要你从同一个地方得到回应,它就会通过。但是,当您的消息无法通过他的 NAT 时,您如何获得响应?当然,他也做同样的事情。其中一条消息可能会丢失,但另一条消息会通过,然后你们都已准备好并可以进行交流。您需要定期发送 keep-alives,这样路由器就不会忘记您正在通信,但除此之外,真的没有什么棘手的。
唯一的问题是您需要知道其他对等方的公共 IP 地址,以及他希望您来自的端口,而他也需要了解您的相关信息。这就是您需要服务器的原因——充当对等点之间的介绍者。
打孔功能适用于大多数家庭网络中的 UDP。它不适用于来自许多家庭网络的 TCP,或者来自许多公司网络的 UDP 或 TCP。 (此外,在公司网络中,您可能有多层 NAT,这意味着您需要在每个接口上都需要引入器,而不仅仅是互联网上的一个,或者对称 NAT,这是无法打孔的。)
您可以使用STUN(或类似)服务,例如 ICE 或 TURN。这仅在有 ICE、TURN 等服务要使用时才有效——这对于不同家庭 NAT 上的两个对等点通常不是这种情况,除非您部署自己的服务器并构建一个介绍器来提供帮助,并且如果您是要做到这一点,你可以只使用打孔。但在企业环境中,这可能是为 P2P 应用程序提供连接的最佳方式。
最后,您可以让用户手动配置端口转发并将转发的端口号输入您的问题。这并不理想,但您应该始终将其作为后备提供(可能仅用于企业部署的应用除外),因为没有其他方法适用于您的所有用户。
我相信 Skype 使用所有这些。如果您启用 UPnP,它会尝试对您的路由器进行 IGD。或者您可以将其配置为使用 TURN 服务器。或者您可以只输入您手动转发的特定端口。如果您不执行上述任何操作,它会尝试使用 UDP 打孔,并带有 Skype 运行的介绍器。