向255.255.255.255广播UDP数据包

10

第一次发帖,希望这是一个简单的问题:

我需要向一台硬件发送广播包,但当它启动时,它位于不同于我的机器的子网上,为了告诉它将其IP地址重置为我的网络上的IP地址。但是,除非我使用DHCP,否则我似乎无法在自己的子网外进行广播,而最终我将无法使用DHCP。网络上没有路由器,只有我的机器和我要通信的盒子之间的简单交换机,以及其他几台Linux机器。

因此,基本上这个示例代码在Fedora 19的测试环境中可以工作(在我启用DHCP的较大网络上),直到我尝试静态设置我的IP地址:

int main(int argc, char *argv[])
{
    int sock;
    if( (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    {
        perror("socket : ");
        return -1;
    }

    int broadcast = 1;
    if( setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) != 0 )
    {
        perror("setsockopt : ");
        close(sock);
        return -1;
    }

    char *ip = "255.255.255.255";
    char * msg = "Hello World!";

    struct sockaddr_in si;
    si.sin_family = AF_INET;
    si.sin_port   = htons( 4444 );
    inet_aton( ip, &si.sin_addr.s_addr );

    /* send data */
    size_t nBytes = sendto(sock, msg, strlen(msg), 0, 
                    (struct sockaddr*) &si, sizeof(si));

    printf("Sent msg: %s, %d bytes with socket %d to %s\n", msg, nBytes, sock, ip);

    return 0;
}

如果我正在使用DHCP,则输出如下:

Sent msg: Hello World!, 12 bytes with socket 3 to 255.255.255.255

我可以在Wireshark中看到数据包被发送出去。

然后,如果我将我的IP地址静态设置为192.168.100.1,我会得到:

Sent msg: Hello World!, -1 bytes with socket 3 to 255.255.255.255

我在Wireshark中看不到数据包。我可以确认ifconfig中显示的传输(TX)数据包数量没有增加。我尝试禁用防火墙:

sudo iptables -F

但是那没起作用。有人看到我漏掉的东西了吗?我可以广播到192.168.100.255,但这不会到达我需要通信的盒子,例如它可能在192.168.200.10,255.255.255.0上默认设置。如果我改变网络上其他所有设备的网络参数,它就能正常工作,但这不是一个真正的选择。

编辑: 关于一些评论和答案,请注意我并没有使用路由器,只需在我的计算机和其他盒子之间连接一根电线即可复制行为。所以,问题实际上是,为什么Linux没有发送数据包?我显然不知道,但我怀疑Linux本身会丢弃跨子网广播数据包,除非它可以将该决策委托给网络上的另一个机构。无论如何,考虑到我的网络很小,我只能绕过它。


你是否在 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast) 中调整设置以取消广播? - Tony The Lion
1
“DHCP”是广播的一个非常特殊的情况,因为路由器充当中继代理并将DHCP“消息”再次广播到其他子网。如此解释:http://en.wikipedia.org/wiki/Dhcp “在同一子网上的DHCP客户端和服务器通过UDP广播进行通信。如果客户端和服务器位于不同的子网上,则可以使用DHCP Helper或DHCP Relay Agent。请求续订现有租约的客户端可以直接通过UDP单播进行通信,因为此时客户端已经建立了IP地址。” - H_squared
@GPHoit这个交换机是否连接到路由器上? - H_squared
@GPHoit 仔细想想,考虑到您正在使用简单的公共第二层交换机,这样的交换机不会将不同的子网连接在一起。这是由网络层(第3层),例如路由器来完成的。因此,在您的情况下发生的是,交换机接收广播消息并将其转发给同一子网中的所有收件人(因为它无法连接多个子网),然后将消息转发到路由器(您可以说路由器存在于多个子网中,因此它接收到了消息)。但是,路由器会丢弃广播。如前所述,DHCP是一个特殊情况。 - H_squared
@hhachem,但是我的网络上没有路由器 :-) ... 问题在于我的广播数据包根本没有被发送,即sendto失败并显示“网络不可达”。在这种配置下,似乎你无法(至少在Linux中)将广播数据包发送到子网之外。 - GP Hoit
显示剩余2条评论
3个回答

6

我刚遇到了这个问题。一切都很好,直到我删除网关后,当我尝试从套接字发送时,出现网络不可达错误。

由于我使用广播消息来配置我的盒子的网络设置,所以为了使其工作,将网关地址配置不是我的选择。然而,由于我的盒子只有一个网络接口,我找到了以下解决方案:

//绑定到正确的接口以能够在没有默认网关的情况下进行发送 char netif [] =“eth0”; setsockopt(fd,SOL_SOCKET,SO_BINDTODEVICE,netif,sizeof(netif));

有了这个解决方案,我可以在套接字上发送到广播255.255.255.255地址,而不受任何默认网关的限制。只要您知道要使用哪个接口,此解决方案应适用于具有多个网络接口的系统。


我最近在从Red Hat 6升级到Red Hat 7后遇到了这个问题。原来旧的Linux在路由表中配置了默认路由,而新的则不会自动配置此路由。对我来说解决方法是输入:#route add default <ethname>。 - Bob

3

按照定义,广播仅限于一个子网。如果广播逃脱了一个子网并溢出互联网,那将是可怕的。如果您正在寻找跨越子网的方法,您应该看看 组播。还可以参考这里。祝好运!


1
OP只是发送到255.255.255.255,但sendto()失败了。这通常应该可以工作。还要记住,如果您都在同一层2广播域上(您永远不应该这样做,但OP描述他实际上是这样的),则可以广播到不同的IP子网。 - nos
1
嗯,我有点困惑。他提到使用广播方式访问不同子网上的硬件设备。然而,他接着发布了一段代码,但是当更改IP地址时,它显然没有达到预期的效果。无论如何,除非他有一个特殊的路由器(如思科...),可以配置路由器来实现预期的广播。 - H_squared
@ nos:如果子网掩码是255.255.0.0(B类),我相信这将是情况。但他在C类网络上。因此,广播到192.168.100.255将到达192.168.100.X,但不会到达192.168.200.10。 - H_squared
1
是的,但他正在使用广播地址255.255.255.255,在Linux中应该可以做到这一点-而且他没有路由器。这意味着例如您需要1个简单的以太网交换机,您将连接1台PC,该PC位于192.168.100.0/24上,并连接1台PC,该PC位于192.168.200.0/24上。这两个PC现在位于同一个以太网广播域中,并且应该能够看到彼此的广播数据包到255.255.255.255。(它们甚至可以看到(至少使用例如Wireshark)到192.168.100.255或192.168.200.255的广播,尽管它们通常会被网络卡过滤掉。) - nos
@nos,我觉得你已经理解了我的问题——这里没有路由器,只有一个愚蠢的交换机。我甚至可以更简单,只需将交换机拿出来,然后在我的电脑和供应商的硬件之间放一根网线。我明白hhachem说路由器应该负责丢弃广播数据包,但我不明白为什么我的电脑会自己丢弃数据包。255.255.255.255是“不可达”的,这让人感到困惑,因为它并不是需要被“到达”的实际地址,可以这样说。 - GP Hoit
显示剩余3条评论

1
请检查您的默认网关。如果网关的IP位于另一个子网中,则在广播到255.255.255.255地址一段时间后,您将收到错误消息“网络不可达”。顺便说一下,即使网关IP位于另一个子网中,直接发送到子网广播(例如,如果您的IP是192.168.1.1,则发送到192.168.1.255)也可以正常工作。请保留HTML标签。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接