如何忽略自己的广播UDP数据包

12

以下我假设只有一张网络卡。

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

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

但是,我发现很难获取本地IP:使用NULL的getaddrinfo会返回127.0.0.1,使用主机名的getaddrinfo会返回公共IP。有谁能指导我找到实际的子网IP? 我想我可能漏掉了一些非常明显的东西,但是...我仍然没有找到 :)

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


为什么你不利用现有的解决方案,比如mDNS(多播DNS)? - jldupont
mDNS对我的需求来说太复杂了。 - laura
5个回答

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

这是个相当不错的想法,但有点像 hackish - 信息是很容易获取的(ipconfig/ifconfig),所以我应该能够以某种方式提取它。 - laura
可以将“true”更改为应用程序的参数,然后进行脚本处理。我同意这种方法非常不正规。 - Simeon Pilgrim
接受这种方法,虽然有些hacky,但是没有特定的API调用是唯一的方法。此外,我已经传输了一个跟踪值,所以我只需要添加一行额外的代码即可。 - laura

2
在Linux上,您可以使用带有SIOCGIFADDR选项的ioctl获取给定接口的IP地址。但我认为这在Windows上不起作用。因此,您需要像这样做一些奇怪的事情。请注意保留HTML标签。

1

函数getsockname(函数文档)可以获取与特定套接字关联的本地IP地址。如果您在用于发送广播的套接字上调用此函数,则应该看到与recvfrom返回的相同IP地址。


2
在Windows上返回0.0.0.0,在Linux上返回一些奇怪的乱码。 - laura

0

(我假设你正在使用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个声望,所以我不知道是否能够回答问题,感谢Stackoverflow!)

0

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


2
这些是多播选项,与广播无关。 - user207421

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