我有一台运行Ubuntu 16.04的主机通过主要有线网络接口连接到一个网络,并通过USB转以太网适配器连接到另一个网络。使用tcpdump
,我能够验证两个网络接口上的传入多播数据包。但是,我的应用程序没有从辅助接口接收任何多播数据。如果我断开电缆到主接口,然后重新启动我的应用程序,那么我确实从辅助接口接收数据。只有两个接口都连接,应用程序才会从辅助接口接收。
答案 0 :(得分:1)
我发现了类似的问题(带有USB转以太网适配器的Raspberry Pi Zero无法响应mDNS查询)。要确定您的问题是否相同,您的应用是否会在同时运行tcpdump时正确接收多播流量?运行带有--no-promiscuous-mode
的tcpdump是否看不到多播流量?
如果你的回答都是肯定的,那么我找到的解决方法只是ip link set eth0 promisc on
。我不知道它是否是硬件错误(我使用的是控创DM9601适配器,ID 0FE6:9700)或驱动程序错误,但无论哪种方式,启用混杂模式似乎都能为我修复多播接收。或者,您可以尝试更好的USB到以太网适配器。
答案 1 :(得分:0)
The ip_mreq
stucture is passed as the option value for the IP_ADD_MEMBERSHIP
socket option to join a multicast group. From the Multicast programming HOWTO from the The Linux Documentation Project:
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.
The IP_MULTICAT_IF
socket option is also relevant on a multihomed host to set the outbound interface for multicast data sent via the socket. More information on these socket options, the ip_mreq
structure, and the newer ip_mreqn
stucture is found here.
For those using Boost on a multihomed host, you will need to use the native handle to join the group on specific interfaces. As of Boost 1.58 running on Ubuntu 16.04, the socket option abstraction ip::multiast::join_group()
joins the group on an interface of the kernel's choosing and does not allow the developer to specify an interface. The socket option abstraction ip::multicast::outbound_interface()
controls the outbound interface but does not affect which interface the socket receives on.
Here is a code sample to join a group on a specific interface based on the local interface IP address:
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 ...
}