多个 UDP 套接字和多个客户端

Multiple UDP sockets and multiple clients

我必须使用 UDP 套接字编写程序,但我无法理解在我遇到的情况下我应该做什么。

我有一个服务器和一个客户端。服务器在 INADDR_ANY 套接字上接收数据报,并且对于出现的每个唯一客户端,它会向 () 发送大量信息。每个客户端还定期向服务器发送数据。

对于每个联系监听套接字的客户端,我们称它为 0,我为其创建一个单独的套接字,这样我就可以向它发送数据而不会阻塞套接字 0。我想要做的是将所有通信移动到一个特定的新套接字的客户端。我可以这样做吗?目标是使通信更轻松、高效并避免堵塞任何套接字。

所以我找不到答案的问题是:

我知道 TCP 对此效果更好,但我必须使用 UDP。我应该怎么做?是否有公认的 "standard" 处理此类情况?

评论:我觉得我误解了 UDP 套接字,但与 TCP 相比,关于它的教程真的很少。

What I want to do is move all communication with a specific client to the new socket. Can I do that?

您可以创建一个新的 UDP 套接字,将其 bind() 到另一个端口,然后指示客户端开始将流量发送到新套接字的端口而不是通常的端口;但请注意,这样做并没有真正获得任何优势。

If not, won't having all the clients write to socket 0 clog it if I won't do recvfrom often enough?

是的,但通常的解决方案是经常调用 recvfrom() 以跟上传入流量,and/or 增加其 SO_RECVBUF 缓冲区大小以使其传入-数据缓冲区足够大,不太可能变满。 确保足够频繁地调用 recvfrom() 的一种方法是创建一个单独的线程,该线程只在循环中调用 recvfrom(),然后将数据移交给另一个线程以进行更密集的处理。 运行 如果可能,此网络线程具有更高的优先级,以确保它不会被其他线程阻止CPU。

If it's possible to recv data from a specific client on a separate socket, will that data come to BOTH socket 0 and the specific socket?

如果您有两个线程都在同一个套接字上调用 recvfrom(),那么任何给定的传入 UDP 数据包都将被传送到一个线程或另一个线程,并且无法预测哪个线程将接收哪个数据包 --抽签的运气取决于特定线程在其上调用 recvfrom() 时套接字传入缓冲区中的下一个数据包是什么。一般来说,让多个线程访问单个套接字不是推荐的设计。

I know that TCP would work better for this but I have to use UDP. How should I do this? Is there an accepted "standard" of handling such situations?

我不知道什么是 "standard",但我通常有一个专用的 I/O 线程,它除了读取(必要时写入)UDP 套接字外什么都不做。它将 UDP 套接字设置为非阻塞模式,然后循环 select() 到 recvfrom() 任何传入的 UDP 数据包并附加(以线程安全的方式)传入数据包的数据及其 source-address/port 信息到 FIFO 队列,供其他(对时间不太敏感的)线程取出并稍后处理。这样即使一个数据包(或系列或数据包)需要相对较长的时间来处理,结果也不会是数据包被丢弃(尽管它可能会随着 FIFO 变大而暂时增加 RAM 使用)

@ Jeremy Friesner:你写道:“......即便如此,我的直觉是 non-deterministic/unpredictable 两个套接字中的哪一个接收到任何特定的数据包——如果你的 connect()'套接字收到别人的数据包,我怀疑数据包会得到 dropped/filtered”。 这正是我在 Linux 和 lwIP 中调查的结果:后来创建的套接字(具有更高的 fd 编号)是接收套接字,而另一个不接收。