【问题标题】:How to ignore your own broadcast udp packets如何忽略自己的广播 udp 数据包
【发布时间】:2010-12-18 05:45:23
【问题描述】:

对于以下我假设一个网卡。

我的程序中有一个组件,旨在让子网中的其他人知道它的存在。为此,我实现了一个解决方案,每当程序启动时(以及之后定期),它都会向INADDR_BROADCAST 发送一个广播——任何在所需端口上监听的人都会记住它来自何处以供以后使用。

问题在于我不想记住自己的广播。我认为理论上这很容易做到 - 只需找出本地 ip 并与您在recvfrom 中获得的内容进行比较。

但是,我发现很难获得本地 IP:getaddrinfo 带有 NULL 返回 127.0.0.1getaddrinfo 带有主机名返回公共 IP。谁能指出我找到实际子网 ip 的方向?我想我一定在这里遗漏了一些非常明显的东西,但是……我仍然想念它:)

注意:我已经阅读了其他关于广播的 SO 问题,尤其是这个:UDP-Broadcast on all interfaces,但我还没有解决多接口问题。

【问题讨论】:

  • 您为什么不利用现有的解决方案,例如 mDNS(Multicast-DNS)?
  • mDNS 对于我的需求来说太复杂了。

标签: c networking udp broadcast berkeley-sockets


【解决方案1】:

在启动时,您可以广播一条具有随机(但跟踪)值的不同消息,然后等待该消息,发现您自己的地址,从那时起,您可以发送正常消息,而忽略您的来源消息。

【讨论】:

  • 这是一个很好的主意,但它有点骇人听闻 - 信息很容易获得(ipconfig/ifconfig)所以我应该能够以某种方式提取它
  • true,您可以将其更改为应用程序的参数,然后进行脚本编写。我同意这很hackish
  • 接受这一点是因为,虽然很老套,但在没有特定 API 调用的情况下是唯一的方法。另外,我已经在传输一个跟踪值,所以我只需要添加一行额外的代码。
【解决方案2】:

在 linux 上,您可以使用带有 SIOCGIFADDR 选项的 ioctl 获取给定接口的 IP 地址。不过,我认为这不适用于 Windows。为此,您必须做一些愚蠢的事情,例如 this

【讨论】:

    【解决方案3】:

    getsockname (function documentation) 可以发现与特定套接字关联的本地 IP 地址。如果您在用于发送广播的套接字上调用它,您应该会看到recvfrom 返回的相同 IP 地址。

    【讨论】:

    • 在 Windows 上返回 0.0.0.0,在 linux 上返回一些奇怪的乱码。
    【解决方案4】:

    搜索 scoket 选项并查看这些选项是否有效: IP_MULTICAST_LOOP,IP_BLOCK_SOURCE

    【讨论】:

    • 这些是多播选项。与广播无关。
    【解决方案5】:

    (我假设您在 Windows 上工作)

    GetIpAddrTable 正是这样做的!它返回有关所有网络接口的数据,IP 地址就在其中。获得它们有一些技巧,但并不比 Winsocks 的其他部分多。

    这是一个准备编译的 54 行示例,它使用 IP 和网络掩码打印您的所有网络接口,并过滤您的本地回调 (127.0.0.1),因为您很可能不希望这样做,而且它总是在那里,所以你不能忽略它:

    (使用 msvc 19、windows 10,链接到 Iphlpapi.lib 和 Ws2_32.lib)

    #include "stdio.h"
    #include "Winsock2.h"
    #include "Iphlpapi.h"
    
    int main(){
        int error;
    
        ULONG size = 0;
        MIB_IPADDRTABLE* meta_table = nullptr;
    
        error = GetIpAddrTable(meta_table, &size, false);
        if(error != ERROR_INSUFFICIENT_BUFFER)
            return -1;
    
        meta_table = (MIB_IPADDRTABLE*)malloc(size);
    
        error = GetIpAddrTable(meta_table, &size, false);
        if(error != NO_ERROR)
            return -1;
    
        int os_interface_count = meta_table->dwNumEntries;
    
        for(int i = 0; i < os_interface_count; i++){
    
            printf("interface:\n");
    
            {
                in_addr mask;
                in_addr address;
                address.S_un.S_addr = meta_table->table[i].dwAddr;
                mask.S_un.S_addr = meta_table->table[i].dwMask;
    
                printf("index:     %d\n", meta_table->table[i].dwIndex);
                printf("address:   %s\n", inet_ntoa(address));
                printf("mask:      %s\n", inet_ntoa(mask));
            }
    
            {
                in_addr callback_address;
                callback_address.S_un.S_un_b.s_b1 = 127;
                callback_address.S_un.S_un_b.s_b2 = 0;
                callback_address.S_un.S_un_b.s_b3 = 0;
                callback_address.S_un.S_un_b.s_b4 = 1;
    
                if(meta_table->table[i].dwAddr == callback_address.S_un.S_addr)
                    printf("local callback!\n");
    
            }
    
        }
    
        free(meta_table);
        return 0;
    }
    

    在我的机器上产生这个输出:

    interface:
    index:     7
    address:   192.168.56.1
    mask:      255.255.255.0
    interface:
    index:     1
    address:   127.0.0.1
    mask:      255.0.0.0
    local callback!
    interface:
    index:     11
    address:   192.168.178.181
    mask:      255.255.255.0
    

    唯一真正奇怪的事情是第一次调用GetIpAddrTable,它只是为您提供了您需要为缓冲区分配的大小。我认为其余的代码是非常不言自明的,如果不是,我是来提问的。 (我没有 50 Rep,所以我不知道我是否能够回答问题,谢谢 Stackoverflow!)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-27
      • 1970-01-01
      相关资源
      最近更新 更多