Linux 所有接口上的UDP广播

Linux 所有接口上的UDP广播,linux,udp,posix,broadcast,Linux,Udp,Posix,Broadcast,在具有有线和无线接口(例如192.168.1.x和192.168.2.x子网)的Linux系统上,我希望通过所有可用接口(即有线和无线接口)发送UDP广播 目前,我将发送到Inadr_BROADCAST,但似乎广播仅通过其中一个接口发送,并不总是相同的,后续广播可能会使用另一个接口 有没有一种方法可以通过每个接口发送UDP广播 您不能让一个sendto在每个接口上生成一个数据包-通常情况下,尽管每个sendto只传输一个数据包,但还是会产生碎片 您需要为每个接口发送一次数据包,并且: 使用低电平

在具有有线和无线接口(例如192.168.1.x和192.168.2.x子网)的Linux系统上,我希望通过所有可用接口(即有线和无线接口)发送UDP广播

目前,我将发送到Inadr_BROADCAST,但似乎广播仅通过其中一个接口发送,并不总是相同的,后续广播可能会使用另一个接口

有没有一种方法可以通过每个接口发送UDP广播

您不能让一个sendto在每个接口上生成一个数据包-通常情况下,尽管每个sendto只传输一个数据包,但还是会产生碎片

您需要为每个接口发送一次数据包,并且:

使用低电平setsockopt?调用以选择出站接口

发送到每个已知接口的特定广播地址

但是,如果您试图执行某种类型的发现机制,例如您期望响应的设备实际上没有在与其连接的接口相同的子网中正确配置IP地址,则后者不适用。

来自UNIX套接字常见问题解答:

包括 ifdef WIN32 包括 包括 包括 其他的 包括 包括 包括 包括 包括 包括 包括 恩迪夫 包括 包括 typedef无符号长uint32; 如果已定义uu FreeBSD uu124; |已定义| |已定义uu苹果u124; |已定义124; linux__ 定义使用\u GETIFADDRS 1 包括 静态uint32 SOCKADDRTOUNT32结构sockaddr*a { 返回a&&a->sa_family==AF_INET?ntohlstruct sockaddr_in*a->sin_addr.s_addr:0; } 恩迪夫 //将数字IP地址转换为其字符串表示形式 静态无效Inet_NtoAuint32地址,字符*ipbuf { sprintfipbuf,%li.%li.%li,地址>>24&0xFF,地址>>16&0xFF,地址>>8&0xFF,地址>>0&0xFF; } //将IP地址的字符串表示转换为其等效数字 静态uint32 Inet_AtoNconst char*buf { //net_服务器莫名其妙地没有这个功能;所以我将假装它 uint32 ret=0; int shift=24;//首先填写MSB bool startQuad=true; 当换档>=0&&*buf时 { 如果开始 { unsigned char quad=unsigned char atoibuf; ret |=UINT32四个ifa|U地址; uint32 maskAddr=sockaddrtoint32p->ifa\u网络掩码; uint32 dstAddr=sockaddrtoint32p->ifa_dstAddr; 如果iFaddr>0 { char ifaAddrStr[32];Inet_NtoAifaAddr,ifaAddrStr; char maskAddrStr[32];Inet_NtoAmaskAddr,maskAddrStr; char dstAddrStr[32];Inet_NtoAdstAddr,dstAddrStr; printf找到的接口:name=[%s]desc=[%s]address=[%s]netmask=[%s]broadcastAddr=[%s]\n,p->ifa_name,不可用,ifaAddrStr,maskAddrStr,dstAddrStr; } p=p->ifa\U下一步; } freeifaddrsifap; } elif定义的Win32 //Windows XP风格的实现 //改编自http://msdn2.microsoft.com/en-us/library/aa365917.aspx //现在获取Windows的IPv4地址表。我们再次调用GetIPAddressTable //多次,以便正确处理潜在的竞争条件。 MIB_IPAddressTable*ipTable=NULL; { ULONG bufLen=0; 对于int i=0;iIpAddressList; whileipddr { 如果Inet\u AtoNipAddr->IpAddress.String==ntohlrow.dwAddr { 名称=下一个->适配器名称; desc=下一步->说明; 打破 } ipAddr=ipAddr->Next; } 下一步=下一步->下一步; } } char-buf[128]; 如果name==NULL { sprintfbuf,未命名-%i,i; name=buf; } uint32 ipAddr=ntohlrow.dwAddr; uint32 netmask=ntohlrow.dwMask; uint32-baddr=ipAddr&netmask; 如果row.dwBCastAddr baddr |=~netmask; char ifaAddrStr[32];Inet_NtoAipAddr,Ifaddrstr; char maskAddrStr[32];马斯卡德斯特里内特·恩图阿内特马斯克; char dstAddrStr[32];Inet_NtoAbaddr,dstAddrStr; printf找到的接口:name=[%s]desc=[%s]地址=[%s]网络掩码=[%s]广播地址=[%s]\n,name,desc?desc:不可用,ifaAddrStr,maskAddrStr,dstAddrStr; } freepAdapterInfo; 可自由书写; } 其他的 //不知道我们在干什么! 错误:不知道如何在此操作系统上实现PrintNetworkInterfaceInfo! 恩迪夫 } 整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型整型** { 打印网络接口信息; 返回0; }
首先,你应该考虑广播过时,特别是InDrdRel广播255.255.255.255。你的问题正好突出了广播不适合的原因之一。它应该和你一起死去。请注意,IPv6甚至没有使用广播多播的概念

INADDR_广播仅限于lo cal link。现在,它唯一可见的用途是用于DHCP自动配置,因为此时,客户端还不知道它连接到哪个网络

对于单个sendto,只生成一个数据包,传出接口由linux上操作系统的路由表ip route确定。您不能使用单个send生成多个数据包,您必须迭代所有接口,使用原始套接字或使用setsockopt…、SOL_socket、SO_BINDTODEVICE、ethX将套接字绑定到设备,以绕过OS路由表发送每个数据包。这需要根权限。这不是个好办法

相反,由于INADDR_广播无论如何都不会路由,您可以通过迭代每个接口并将数据包发送到其广播地址来实现几乎相同的目的。例如,假设您的网络具有255.255.255.0/24掩码,则广播地址为192.168.1.255和192.168.2.255。对于每个地址,请致电sendto一次,您就完成了目标


编辑:修复了有关INADDR_广播的信息,并用有关SO_BINDTODEVICE的信息补充答案。

如果INADDR_广播确实意味着这是很久以前的事了。当我今晚见到RFC1的作者时,我会问他:在最近的记忆中,它总是映射到本地网段的MAC地址。定向广播过去由路由器处理,但现在由于安全原因被阻止。好的,我检查了RFC 919,似乎255.255.255.255的第一个定义是直接邻居。出于某种原因,我认为整个互联网是用0.0.0.0/0表示的,结果是network=0.0.0.0,brdcast=255.255.255.255。修正了答案。好的,很高兴修正了。现在,关于IPv6的评论,别忘了广播在语义上等同于TTL 1多播,只是它在第2层不使用广播帧。@Juliano为了发送到广播地址,不应该设置setsockopt…、SOL_SOCKET、SO_broadcast和variable_with_one吗?如果我尝试不设置该选项,则会收到一条“权限被拒绝”错误消息。FWIW,在Windows上,带有INADDR_广播的sendto会为每个接口生成一个数据包。上面链接的代码显示了如何使用getIFADRS和Win32特定的getIPAddTable枚举所有接口,只是为了说明:每个接口一个数据包意味着每个接口一个套接字。