在具有多个接口的 linux 主机上接收多播

Receiving multicast on linux host with multiple interfaces

我有一台主机 运行 Ubuntu 16.04 通过主要有线网络接口连接到一个网络,并通过 USB 转以太网适配器连接到另一个网络。使用 tcpdump,我能够验证两个网络接口上传入的多播数据包。但是,我的应用程序没有从辅助接口接收到任何多播数据。如果我断开连接到主接口的电缆,然后重新启动我的应用程序,那么我确实会从辅助接口接收数据。只有连接了两个接口,应用程序才不会从辅助接口接收。

我发现了类似的问题(Raspberry Pi USB 转以太网适配器为零,无法响应 mDNS 查询)。要确定您的问题是否相同,您的应用是否在 运行 tcpdump 同时正确接收多播流量? 运行 tcpdump with --no-promiscuous-mode 是否看不到多播流量?

如果您对两者的回答都是肯定的,那么我找到的解决方法就是 ip link set eth0 promisc on。我不知道这是硬件错误(我使用的是 Kontron DM9601 适配器,ID 0FE6:9700)还是驱动程序错误,但无论哪种方式,启用混杂模式似乎都为我解决了多播接收问题。或者,您可以尝试使用更好的 USB 转以太网适配器。

ip_mreq 结构作为 IP_ADD_MEMBERSHIP 套接字选项的选项值传递以加入多播组。来自 Linux 文档项目的 Multicast programming HOWTO

The first member, imr_multiaddr, holds the group address you want to join. Remember that memberships are also associated with interfaces, not just groups. This is the reason you have to provide a value for the second member: imr_interface. This way, if you are in a multihomed host, you can join the same group in several interfaces. You can always fill this last member with the wildcard address (INADDR_ANY) and then the kernel will deal with the task of choosing the interface.

IP_MULTICAT_IF套接字选项也与多宿主主机相关,用于设置通过套接字发送的多播数据的出站接口。有关这些套接字选项、ip_mreq 结构和较新的 ip_mreqn 结构的更多信息,请参见 here.

对于在多宿主主机上使用 Boost 的用户,您将需要使用本机句柄在特定接口上加入组。从 Ubuntu 16.04 的 Boost 1.58 运行 开始,套接字选项抽象 ip::multiast::join_group() 在内核选择的接口上加入组,并且不允许开发人员指定接口。套接字选项抽象ip::multicast::outbound_interface()控制出接口但不影响套接字在哪个接口上接收。

这是一个代码示例,用于根据本地接口 IP 地址加入特定接口上的组:

struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(discovery_ip);
mreq.imr_interface.s_addr = inet_addr(local_interface_ip);
if(setsockopt(socket_.native_handle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
    ... handle error ...
}