所有接口上的 UDP 广播
在具有有线和无线接口(例如 192.168.1.x 和 192.168.2.x 子网)的 Linux 系统上,我想发送通过所有可用接口(即通过有线和无线接口)发出的 UDP 广播)。
目前我 sendto() 到 INADDR_BROADCAST,但是似乎广播仅通过其中一个接口发送(并不总是相同,后续广播可能使用另一个接口)。
有没有一种方法可以发送通过每个接口发出的 UDP 广播?
On a Linux system with a wired and a wireless interface (e.g. 192.168.1.x and 192.168.2.x subnets) I want to send a UDP broadcast that goes out via ALL available interfaces (i.e. both through the wired and the wireless interface).
Currently I sendto() to INADDR_BROADCAST, however it seems that the broadcast only is sent through one of the interfaces (not always the same and subsequent broadcasts may use the other interface).
Is there a way that I can send a UDP broadcast that goes out through every single interface?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先,您应该考虑广播已过时,特别是
INADDR_BROADCAST
(255.255.255.255)。 你的问题恰恰突出了广播不合适的原因之一。 它应该与 IPv4 一起消亡(希望如此)。 请注意,IPv6 甚至没有广播的概念(而是使用多播)。INADDR_BROADCAST
仅限于本地链接。 如今,它唯一可见的用途是 DHCP 自动配置,因为此时客户端尚不知道它连接到哪个网络。使用单个
sendto()
,仅生成单个数据包,并且传出接口由操作系统的路由表(Linux 上的iproute
)确定。 您不能让单个sendto()
生成多个数据包,您必须迭代所有接口,并且使用原始套接字或使用setsockopt( 将套接字绑定到设备) ..., SOL_SOCKET, SO_BINDTODEVICE, "ethX")
绕过操作系统路由表发送每个数据包(这需要 root 权限)。 这不是一个好的解决方案。相反,由于
INADDR_BROADCAST
无论如何都不会被路由,因此您可以通过迭代每个接口并将数据包发送到其广播地址来实现几乎相同的效果。 例如,假设您的网络具有 255.255.255.0 (/24) 掩码,则广播地址为 192.168.1.255 和 192.168.2.255。 对每个地址调用一次sendto()
即可实现您的目标。编辑:修复了有关
INADDR_BROADCAST
的信息,并用有关SO_BINDTODEVICE
的信息补充了答案。First of all, you should consider broadcast obsolete, specially
INADDR_BROADCAST
(255.255.255.255). Your question highlights exactly one of the reasons that broadcast is unsuitable. It should die along with IPv4 (hopefully). Note that IPv6 doesn't even have a concept of broadcast (multicast is used, instead).INADDR_BROADCAST
is limited to the local link. Nowadays, it's only visible use is for DHCP auto-configuration, since at such time, the client will not know yet in what network it is connected to.With a single
sendto()
, only a single packet is generated, and the outgoing interface is determined by the operating system's routing table (ip route
on linux). You can't have a singlesendto()
generate more than one packet, you would have to iterate over all interfaces, and either use raw sockets or bind the socket to a device usingsetsockopt(..., SOL_SOCKET, SO_BINDTODEVICE, "ethX")
to send each packet bypassing the OS routing table (this requires root privileges). Not a good solution.Instead, since
INADDR_BROADCAST
is not routed anyway, you can achieve almost the same thing by iterating over each interface, and sending the packet to its broadcast address. For example, assuming that your networks have 255.255.255.0 (/24) masks, the broadcast addresses are 192.168.1.255 and 192.168.2.255. Callsendto()
once for each of these addresses and you will have accomplished your goal.Edit: fixed information regarding to
INADDR_BROADCAST
, and complementing the answer with information aboutSO_BINDTODEVICE
.您无法让单个
sendto()
在每个接口上生成数据包 - 一般来说(尽管有碎片),每个sendto()
传输一个数据包。您需要为每个接口传输一次数据包,并且可以:
使用低级 (
setsockopt()
?) 调用来选择出站接口发送到每个已知接口的特定广播地址
但后者不是适合如果您尝试执行某种发现机制,这样您期望响应的设备实际上并未正确配置与它们所连接的接口位于同一子网中的 IP 地址。
You can't have a single
sendto()
generate a packet on every interface - in general (fragmentation notwithstanding) it's one packet transmitted for eachsendto()
.You'll need to transmit the packet once for each interface and either:
use low-level (
setsockopt()
?) calls to select the outbound interfacesend to the specific broadcast address for each known interface
the latter is however not suitable if you're trying to do some sort of discovery mechanism, such that the devices you're expecting to respond aren't actually correctly configured with an IP address in the same subnet as the interface they're connected to.
来自 Jeremy 的 UNIX Socket 常见问题解答解决方案:
From Jeremy's solution on UNIX Socket FAQ: