boost::asio 中的 NAT 打孔

Posted

技术标签:

【中文标题】boost::asio 中的 NAT 打孔【英文标题】:NAT Hole Punching in boost::asio 【发布时间】:2021-05-03 13:22:58 【问题描述】:

我正在尝试使用 boost::asio 实现 NAT 打孔。据我了解,NAT 打孔是这样工作的(UDP/TCP):

    客户端 A 绑定到一个端口并连接到服务器 S,客户端 B 也这样做。 当S收到请求和匹配时,将A的ip和端口发送给B,B发送给A。 A 和 B 收到对方的 ip 和端口,现在他们从同一个端口向对方发送消息并形成连接(因为他们正在等待回复?)

所以在 boost::asio 中,我能够完成步骤 1-2,但是由于两个客户端都没有端口转发,如果我尝试从一个客户端连接到另一个客户端,它只会给我类似的错误“客户端主动拒绝连接”或“客户端无响应”(令人惊讶的是,这两个客户端即使使用相同的功能也会出现不同的错误)。

如果没有成功的async_connectasio::tcp::socket::connect,我似乎无法运行任何asio::async_write。当然,当目标端口没有被转发时,这两个连接函数都会给我错误。

那么在这种情况下我该如何实现 NAT 打孔,我是否在 boost::asio 中遗漏了什么?任何帮助表示赞赏!谢谢。

【问题讨论】:

我建议您改进您的问题,添加一些示例,一些代码并使其更清晰,看看这里 => How to create a Minimal, Reproducible Example 嗨,我已经编辑了一些关于我正在使用的功能的更多信息。我可以知道您的问题中有哪些不清楚的地方吗?谢谢! Sam,这个问题本身就很好,我的意思是如果你有一些代码可以分享更适合堆栈溢出指南。不幸的是,由于我不是 C++ 开发人员,因此我无法回答您的问题,但我知道 Stack Overflow 以及它的工作原理。您应该始终提供一些源代码,以便该领域的用户专家(在这种情况下为 C++)可以更好地帮助您,不仅您将获得更快的答案,而且还可以获得更高质量的答案,避免被否决甚至关闭问题是否不够清楚。只是一个建议 WP: as a result of the connections using valid port numbers, restrictive firewalls or routers accept and forward the incoming packets on each side - 路由器/防火墙似乎没有合作完成这项工作。 【参考方案1】:

基于“客户端主动拒绝连接”错误,我假设您正在尝试 TCP 连接。 UDP 和 TCP 打洞的工作方式存在根本区别。

3。 A和B收到对方的ip和端口,现在他们从同一个端口互相发送消息并形成连接(因为他们期待回复?)

这不是 TCP 打孔的工作方式。由于 TCP 是点对点的,在第 3 步中您必须预测 A 或 B 的下一个传入端口,并且 A 或 B 需要尝试使用预测的端口建立新连接另一边。显然,有许多不同的 NAT 实现,并不总是能够可靠地预测端口分配,尤其是在运营商级 NAT 的情况下。有关详细信息,请参阅TCP hole punching。作为 TCP 打孔的替代方法,请查看 UPnP 以添加端口转发。

【讨论】:

我明白了,感谢您的纠正,我是在描述 UDP 打孔吗?但是,关于预测另一个客户端的端口,我能够验证两个客户端都从与服务器 S 使用的端口相同的端口发送连接,因此服务器 S 确实传递了正确的端口号,所以似乎不需要预测。我知道它 requires the use of the SO_REUSEADDR on the TCP sockets ,所以我也确保它也打开了。不过,我现在先试试 UDP。感谢您的回复! 至于 UPnP,我已经将其作为备用方案,但不幸的是,我所在国家/地区的主要 ISP 已默认禁用其用户调制解调器上的 UPnP (IKR),所以我不能依赖在那。 NAT PMP 也是如此。不过还是谢谢你的建议。 是的,您描述了 UDP 打孔。如果您的 NAT 使用端口保留分配方案,那么您可以简单地分配一个新端口并通过服务器(或 UDP)与另一端通信。然后按照TCP hole punching 中的说明继续建立 TCP 连接。

以上是关于boost::asio 中的 NAT 打孔的主要内容,如果未能解决你的问题,请参考以下文章

使用 boost::asio::spawn 生成的 asio 处理程序中的 boost::property_tree::read_xml 段错误

strand 在 boost asio 中的优势是啥?

Boost ASIO 中的拍卖

Boost asio 中的 TCP 客户端

Boost::ASIO HTTP POST 中的空正文

如何确定是不是有数据可从 boost::asio 中的套接字读取?