从客户端接收到第一个数据包后,C ++ UDP Socket无法从服务器发送回客户端

Posted

技术标签:

【中文标题】从客户端接收到第一个数据包后,C ++ UDP Socket无法从服务器发送回客户端【英文标题】:C++ UDP Socket not working to send back from server to client after receiving first packets from client 【发布时间】:2020-10-01 19:49:01 【问题描述】:

用 C++ 编写一个 UDP 客户端-服务器应用程序(在过去 15 年中用多种语言编写了很多次),但不知何故,这个应用程序无法正常工作。

目前我无法发布实际代码或最小的可重现应用程序,但如果有人可以通过屏幕共享帮助快速解决此问题,我愿意为实时帮助付费。

我认为这是 C++ 套接字的特殊性,以及我在这个非常复杂的特定应用程序中使用它们的方式。

基本上问题是客户端不会收到从服务器发送到客户端的数据包,只有当所述客户端位于单独的 nat 上时。 当在同一个本地网络中并使用他们的本地 IP 时,一切都按预期工作。

这是我正在做的事情:

    客户端 sendto(...) 使用特定服务器主机和端口 12345 通过 UDP 向服务器发送数据包(并不断发送这些信息) 在另一个线程上,客户端 bind(...) 在端口 12345 和“0.0.0.0”上,并尝试循环访问 poll()recvfrom()(当客户端在单独的 nat 上时,这里的轮询始终返回 0) 服务器 bind() 在端口 12345 和“0.0.0.0”然后 poll()recvfrom() 在一个循环中 从客户端接收到第一条 UDP 消息后,它会启动一个线程用于发送 UDP 消息在新的套接字上返回给客户端,使用 sockaddr_in,它从recvfrom() 得到传递sendto() 命令。

结果:服务器完美接收来自所有客户端的所有消息,并将所有消息发送回所有客户端,但任何不在同一个 NAT 上的客户端将永远不会收到任何消息(poll() 始终返回 0)。

据我了解,当客户端在特定远程端口(本例中为 12345)上向服务器发送 UDP 消息时,它会在其 NAT 上打一个洞,以便它可以从远程接收消息该端口上的服务器...

我测试了五种不同的客户端网络配置:

    与服务器的本地网络,使用本地 IP 地址 (WORKS) 当客户端使用 *** 时与服务器的本地网络因此通过远程 NAT(不起作用) 与服务器的本地网络,但客户端使用 WAN ip 地址连接到服务器(不起作用) 客户端在实际远程网络上,来自朋友的连接,在路由器后面(不起作用) 客户端通过使用我的手机创建的 wifi 热点(不起作用)

对于上述所有测试,服务器正确接收来自客户端的所有通信。

我还尝试将sendto() 的端口强制为12345,而不是使用recvfrom() 中设置的sockaddr_in,同样的问题。

我做错了吗?

如果您想提供帮助但需要查看实际代码,我可以通过屏幕共享实时完成,我会为帮助付费。

谢谢。

另外,如果有人可以将我指向一个很棒的网站,我可以在那里支付非常快速的帮助,请告诉我,我什至不费心搜索谷歌,因为我真的想要尝试这些服务的人的实际建议,而不是广告试图敲诈我......

【问题讨论】:

【参考方案1】:

只有原始的接收方套接字被允许回复客户端,因为在 NAT 中打开端口的是客户端请求。所以要么使用服务器中的同一个socket进行接收和回复,要么获取第二个服务器socket绑定的端口,并通过原始服务器端口传递一个初始消息,以便A可以发送给它并打孔.

当一个套接字是全双工通信对象时,创建两个半双工套接字看起来很奇怪,我会选择第一个选项。

【讨论】:

好的,这似乎是很好的信息,如果这是真的很有帮助!但是,如果使用选项 1,我将不得不完全重写我的网络系统......而且我不确定我是否理解选项 2(这不是我已经在做的吗?)我使用多个半双工套接字的原因是我确实需要每个客户端都在服务器 CPU 上自己的单独线程上,以便尽可能快,而且我的实现不需要客户端和服务器之间的“答案”,而是它们都是进行数据流的两种方式,需要非常低延迟而不是可靠性。 不,绑定第二个服务器套接字后,您需要将一个新的服务器端口号(例如 54321)发送回客户端。要么你选择了那个端口,所以你已经知道它,或者你让系统自动绑定它(例如,通过调用 sendto 而不绑定)。在这种情况下,您需要getsockname() 来获取新分配的端口号。使用已知端口手动调用绑定,或者以动态方式将控制和数据套接字分开,以便您拥有一个分配新分配的端口号的控制套接字。只要客户端发送到端口,它就 好的,它现在可以工作了,我只是将相同的文件描述符传递给我的新套接字抽象,以便它使用相同的原始套接字发送消息......非常感谢!由于某种原因,我似乎无法“接受”您的回答...

以上是关于从客户端接收到第一个数据包后,C ++ UDP Socket无法从服务器发送回客户端的主要内容,如果未能解决你的问题,请参考以下文章

Linux C语言 C/S程序,客户端发送的数据和服务器端接收到的数据不一样,求解

65DHCP服务TFTP服务

Udp打洞原理和源代码。

从 bcp 客户端接收到 colid 6 的无效列长度

TCP套接字服务器如何判断从客户端接收到的数据何时完成?

确定哪个 IP 地址收到了数据包