如何在 UDP 广播中处理同时作为发送方和接收方的客户端
Posted
技术标签:
【中文标题】如何在 UDP 广播中处理同时作为发送方和接收方的客户端【英文标题】:How to handle clients who are both sender and receiver at the same time in UDP broadcast 【发布时间】:2021-12-21 18:31:36 【问题描述】:我陷入以下情况:我有 2 个编写程序 server.c
和 client.c
。最后这两个目标是模拟一个聊天应用程序,类似于Beej's guide(第 6.2 节,第 34 页)中的应用程序。但是,我做一些不同的事情。在我的情况下,服务器只接受新连接(使用 TCP),每当新客户端连接/断开连接时,服务器都会向所有其他仍连接的客户端发送消息并通知它们。同样,客户端通过 TCP 连接到服务器。
服务器不接收客户端的消息,然后将它们发送给所有其他客户端。不。在我的情况下,我想做的是让客户端直接通信,而不是首先将消息发送到服务器。我想通过在每个客户端中使用 UDP 广播来做到这一点。所以基本上,一旦客户端连接到服务器,客户端就完成了与服务器的通信,直到它决定断开连接。在此之前,此客户端将只能发送 UDP 广播 消息或接收 UDP 广播 消息,而无需与服务器交互。
我的问题是我没有在client.c
代码中使用的端口。我可以将sin_family
设置为AF_INET
,我可以将IP 地址设置为广播LAN 地址(以255
结尾),但在client.c
代码中创建广播struct sockaddr_in
时无法设置端口.你看,我正在我的机器上运行这个程序client.c
的多个实例。我应该能够做到这一点,因为服务器在我的机器上,而客户端在虚拟机上,所以我可以并行运行 client.c
的多个实例,因为即使它们有相同的 IP 地址,它们也会有不同的端口.
但我不能bind()
将广播套接字连接到client.c
代码中的端口。它将在我的程序的第一次运行时绑定,但在第二次运行时它会看到该端口已被使用并且会引发错误。即使这样可行,在程序的某个地方我需要使用sendto()
命令发送一条消息,在这里我必须指定我想发送它的位置。现在没有办法知道港口。但我不知道,因为程序的每次运行都会有一个不同的端口,除非我选择一个并绑定它。但是我也不能选择一个,因为在这种情况下我将无法运行程序的多个实例,因为第二次运行会导致错误。
有没有办法解决这个问题?一种无需绑定端口即可在 LAN 中发送广播消息的方法。这应该以这样一种方式完成,即其他客户端可以看到通过 LAN 中的广播发送的内容,同时也不知道发送消息的端口。我知道我可以使用select
同时读取和写入,但我无法进入我选择的阶段,因为我无法为我的客户端分配端口。所以我还没到那里。它基本上归结为有多个客户端,这些客户端可以同时发送 UDP 广播消息和接收 UDP 广播消息,而无需服务器来编排它们。问题是这些客户端没有可使用的端口。
【问题讨论】:
如果您有多个客户端在单个主机上监听不同的端口(甚至使用 SO_REUSEPORT 在同一个端口上),您希望网络堆栈如何知道将数据包多路复用到所有客户端?这不是任何操作系统处理网络数据包的方式。 由于您有多个运行client.c
的VM,您可以将所有VM 的IP 地址设置为不同的。然后他们都可以在同一个端口上监听。因此,如果您的代码被编程为侦听端口 8080。如果您的所有虚拟机都有不同的 IP 地址,它们将能够绑定到套接字。这是你要找的吗?
【参考方案1】:
只要您首先在套接字上设置SO_REUSEADDR
和(在支持它的操作系统下)SO_REUSEPORT
选项,您就可以将多个 UDP 套接字bind()
连接到同一个端口:
int fd = socket(AF_INET, SOCK_DGRAM, 0);
const int trueValue = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &trueValue, sizeof(trueValue));
#ifdef __APPLE__
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &trueValue, sizeof(trueValue));
#endif
// then go on to bind() the socket, using the same (fixed) port number for every client
完成此操作后,您可以在同一主机上创建多个客户端(例如用于测试),它们都将接收彼此的广播数据包(IIRC 也将接收他们自己发送的广播数据包,所以做好准备)。
旁注:如果您的计划是让客户端直接相互通信并且从不与服务器交互,那么您最好摆脱服务器,因为听起来您不需要它来做任何事情(?)
【讨论】:
以上是关于如何在 UDP 广播中处理同时作为发送方和接收方的客户端的主要内容,如果未能解决你的问题,请参考以下文章
发送方和接收方的 google-cast-sdk 音频和字幕手动处理
如何获得 ActiveMQ - 单个发送方和接收方的 FIFO 要求?