如何使多播套接字不接收单播数据?

How can I keep a multicast socket from receiving unicast data

本文关键字:单播 数据 何使 多播 套接字      更新时间:2023-10-16

是否有办法防止套接字加入到多播组从接收单播数据定向在同一端口?

一个socket选项或ioctl可能?我看到了https://msdn.microsoft.com/en-us/library/windows/desktop/ms738712%28v=vs.85%29.aspx,但这似乎只是为了过滤哪些主机可以发送多播,而不是谁可以发送单播。

我正在使用Qt应用程序,所以如果有一种方法可以从Qt的套接字框架内做到这一点,那么很好,如果不是,那么恢复到常规的旧伯克利套接字不是问题。

到目前为止我发现的唯一方法是相当黑客-创建第二个UDP套接字并在绑定多播套接字之前将其绑定到端口。我想一定有更好的东西,虽然我还没找到。

更糟的是:您甚至不能确定您只接收到指向您加入的地址的多播流量。您也可以从运行在同一台机器上的其他进程加入的组中接收多播流量,尽管它们与您的程序无关。

最好的(因为最可移植的)解决方案不是尝试用套接字选项来解决这个问题,而是检查接收到的数据包,找出它们的目标,并丢弃您不想接收的数据包。

您可以使用setsockopt(IP_PKTINFO)和recvmsg()来启用接收到的UDP数据包上的各种有用的元信息,包括通常非常有趣的目标IP地址,在您的情况下是一个多播地址。

将套接字与组播地址绑定,加入组播组,从而配置正确的接口。此方法已在linux和OSX上进行了测试。

auto fd = socket(AF_INET, SOCK_DGRAM,0);
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(MULTICAST_PORT);
inet_pton(AF_INET, INTERFACE_ADDRESS, &sa.sin_addr);
struct sockaddr_in multicast;
multicast.sin_family = AF_INET;
multicast.sin_port = htons(MULTICAST_PORT);
inet_pton(AF_INET, MULTICAST_ADDRESS, &multicast.sin_addr);
struct ip_mreqn req = {};
req.imr_ifindex = INTERFACE_INDEX;
req.imr_multiaddr = multicast.sin_addr;
req.imr_address = sa.sin_addr;
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req, sizeof(req))
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &req, sizeof(req))
bind(fd,(struct sockaddr*)&multicast, sizeof(multicast))

可以用ip_mreq代替ip_mreqn,这样更便于移植,而且不需要接口索引。但是请注意,对于ipv6,加入多播组需要接口索引。

使用Qt,从快速查看https://doc.qt.io/qt-5/qtnetwork-multicastreceiver-receiver-cpp.html,我认为所有你需要做的是设置绑定调用的QHostAddress到groupAddress4。无法保证流量将来自哪个设备。

你的解决方案与另一个套接字将无法移植,因为没有明确的方式,一个端口上的单播流量被调度到多个套接字。(即:可能是轮询,可能是第一个绑定取所有…)