UDP 打孔 (c++/winsock)

Posted

技术标签:

【中文标题】UDP 打孔 (c++/winsock)【英文标题】:UDP Hole Punching (c++/winsock) 【发布时间】:2012-11-30 10:47:14 【问题描述】:

*** 用户!

我有一个必须处理 p2p 的应用程序,这就是我使用 UDP 打孔的方法。但我在实施时遇到了麻烦。希望你能给我一些建议。

我有服务器,它运行完美,可以互相介绍客户端,但客户端无法连接可能是因为我的小 exp 使用套接字。所以,客户端算法是:

    创建 udp 套接字(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);) 通过sendto函数向服务器发送消息 使用 recvfrom 储物柜功能从服务器获取答案

在这 3 个步骤之后,我得到了对等端点。接下来,我尝试通过两种方式连接客户端:

方式1

    使用同一个套接字通过 sendto 函数向对等方发送数据,但传递另一个 sockaddr 使用 recvfrom 储物柜功能收听(此时我收到 WSAECONNRESET 错误)

方式2

    创建新套接字 绑定它 使用它向对等方发送数据 听着

这样,一个客户端绑定失败,另一个客户端监听失败,出现 WSAEADDRINUSEWSAECONNRESET 错误。我显然做错了什么,您的帮助将不胜感激。提前致谢。

附:想分享一篇关于 UDP Hole Punching 的好文章,以帮助那些不熟悉这种技术的人:http://www.brynosaurus.com/pub/net/p2pnat/

【问题讨论】:

试试看这个问题:***.com/questions/8819118/tcp-hole-punching 虽然用UDP做这个一定更容易 【参考方案1】:

如果您将read the documentation 换成recvfrom(),它会说:

WSAECONNRESET

虚拟电路被远程端执行硬或异常关闭重置。应用程序应该关闭套接字;它不再可用。 在 UDP 数据报套接字上,此错误表明之前的发送操作导致 ICMP 端口无法访问消息

这意味着您对sendto() 的调用失败。如果一个或两个客户端都在路由器后面,这是有道理的。根据您的描述(并且缺少代码),您实际上并没有执行任何打孔来打开路由器以允许客户端到客户端的数据包通过。您只向服务器发送了一条消息,它允许客户端到服务器和服务器到客户端的数据包通过。每个客户端和服务器之间需要更多的数据包交换才能在每一端执行打孔,如article you linked to 中详细描述的那样。你真的按照文章说的去做了吗?

【讨论】:

“您实际上并没有进行任何打孔”是什么意思?对于 UDP 打孔,根据文章和 wiki,我需要 2 个客户端和服务器。客户端连接到服务器,服务器在客户端之间共享它们的公共/私有端点。在下一步中,客户端必须使用这些端点直接启动连接。第一个发送的数据包会被 peer2 的 NAT 拒绝,但会在 peer1 的 NAT 上“打一个洞”。之后peer2可以连接peer1。 @JacksonRR:我错过了您将客户端连接在一起的部分。但是,我认为这是正确的行为。来自recvfrom()WSAECONNRESET 告诉您,同一套接字上的先前sendto() 失败了,这就是您希望它执行的操作。 sendto() 无法报告失败。一旦孔被打孔,后续发送将成功。您应该将多个数据包发送到多个地址以正确打孔。你只是在第一次失败后就停止了吗?如果recvfrom() 报告sendto() 失败,则不是错误,只需尝试下一个打孔步骤。 感谢您的回复。我尝试发送更多数据报,忽略第一个错误,但仍然没有好的结果。 recvfrom func 锁定应用程序并忽略其他对等方发送的所有数据包,即使此对等方发送传出数据包到打孔:/ recvfrom() 仅在您使用阻塞套接字时才会阻塞应用程序。在这种情况下,在调用recvfrom() 之前使用select() 知道什么时候需要阅读,以便您可以指定超时。除此之外,请使用您用来打孔的实际代码更新您的问题。

以上是关于UDP 打孔 (c++/winsock)的主要内容,如果未能解决你的问题,请参考以下文章

UDP打孔混乱

UDP打孔无法外接

udp打孔后发送文件

UDP打孔到期[关闭]

UDP打孔可能吗?

UDP 打孔 - 无法到达目的地