简体   繁体   English

C++ 在特定接口上接收多播

[英]C++ receiving multicast on particular interface

Docs on IP_ADD_MEMBERSHIP says: IP_ADD_MEMBERSHIP 上的文档说:

IP_ADD_MEMBERSHIP (since Linux 1.2) Join a multicast group. IP_ADD_MEMBERSHIP(自 Linux 1.2 起)加入多播组。 Argument is an ip_mreqn structure.参数是一个 ip_mreqn 结构。

 struct ip_mreqn { struct in_addr imr_multiaddr; /* IP multicast group address */ struct in_addr imr_address; /* IP address of local interface */ int imr_ifindex; /* interface index */ }; imr_multiaddr contains the address of the multicast group the appli‐ cation wants to join or leave. It must be a valid multicast address (or setsockopt(2) fails with the error EINVAL). imr_address is the address of the local interface with which the system should join the multicast group; if it is equal to INADDR_ANY, an appropriate inter‐ face is chosen by the system. imr_ifindex is the interface index of the interface that should join/leave the imr_multiaddr group, or 0 to indicate any interface.

So I have an interface "eth0" with ip 192.168.1.5.所以我有一个 IP 为 192.168.1.5 的接口“eth0”。 I want to join this interface to multicast group 225.1.1.1.我想将此接口加入多播组 225.1.1.1。 I'm a little bit confused on how to setup ip_mreqn structure properly?我对如何正确设置 ip_mreqn 结构有点困惑? I found 2 possible ways:我发现了两种可能的方法:

1. 1.

ip_mreqn group;
group.imr_multiaddr.s_addr = inet_addr("225.1.1.1");
group.imr_address.s_addr = inet_addr("192.168.1.5");
group.imr_ifindex = 0;

2. 2.

ip_mreqn group;
group.imr_multiaddr.s_addr = inet_addr("225.1.1.1");
group.imr_address.s_addr = htonl(INADDR_ANY);
group.imr_ifindex = if_nametoindex("eth0");

And 3rd way is to use SO_BINDTODEVICE socket option.第三种方法是使用 SO_BINDTODEVICE 套接字选项。

My questions are.我的问题是。

1) What is correct way to join particular interface to multicast group? 1)将特定接口加入组播组的正确方法是什么?

2) What is functional difference between imr_address and imr_ifindex? 2) imr_address 和 imr_ifindex 之间的功能区别是什么?

3) How option SO_BINDTODEVICE could be useful? 3) SO_BINDTODEVICE 选项如何有用?

EDIT: I did some research.编辑:我做了一些研究。

Suppose that I have two network interfaces: eth0 with ip 192.168.1.5 and eth1 with ip 192.168.1.255 and I receive multicast on eth0 with ip 192.168.1.5.假设我有两个网络接口:eth0 的 ip 为 192.168.1.5 和 eth1 的 ip 为 192.168.1.255,我在 eth0 上接收多播,ip 为 192.168.1.5。

These ways work properly (I get multicast messages on eth0):这些方法正常工作(我在 eth0 上收到多播消息):

group.imr_address.s_addr = inet_addr("192.168.1.5");
group.imr_ifindex = 0;

or要么

group.imr_address.s_addr = htonl(INADDR_ANY);
group.imr_ifindex = if_nametoindex("eth0");

or obviously或者很明显

group.imr_address.s_addr = inet_addr("192.168.1.5");
group.imr_ifindex = if_nametoindex("eth0");

and even乃至

group.imr_address.s_addr = inet_addr("192.168.1.255");
group.imr_ifindex = if_nametoindex("eth0");

And these ways do not (I don't get multicast messages on eth0):而这些方式没有(我没有在 eth0 上收到多播消息):

group.imr_address.s_addr = inet_addr("192.168.1.5");
group.imr_ifindex = if_nametoindex("eth1");

and

group.imr_address.s_addr = inet_addr("192.168.1.255");
group.imr_ifindex = if_nametoindex("eth1");

I've always used the older struct ip_mreq instead of struct ip_mreqn , as both are supported.我一直使用旧的struct ip_mreq而不是struct ip_mreqn ,因为两者都受支持。 This struct doesn't have the index field, so it's less ambiguous as to what you need to set.这个结构没有 index 字段,所以你需要设置的内容不那么模糊。

struct ip_mreq
  {
    /* IP multicast address of group.  */
    struct in_addr imr_multiaddr;

    /* Local IP address of interface.  */
    struct in_addr imr_interface;
  };

You would then set it like this:然后你可以这样设置:

struct ip_mreq group;
group.imr_multiaddr.s_addr = inet_addr("225.1.1.1");
group.imr_interface.s_addr = inet_addr("192.168.1.5");

ip_mreqn is used to find network interface devices in the kernel source code at linux/net/ipv4/igmp.c (linux 5.13), as follow. ip_mreqn用于在linux/net/ipv4/igmp.c (linux 5.13) 的内核源代码中查找网络接口设备,如下所示。

static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
{
    struct net_device *dev = NULL;
    struct in_device *idev = NULL;

    if (imr->imr_ifindex) {
        idev = inetdev_by_index(net, imr->imr_ifindex);
        return idev;
    }
    if (imr->imr_address.s_addr) {
        dev = __ip_dev_find(net, imr->imr_address.s_addr, false);
        if (!dev)
            return NULL;
    }

    if (!dev) {
        struct rtable *rt = ip_route_output(net,
                            imr->imr_multiaddr.s_addr,
                            0, 0, 0);
        if (!IS_ERR(rt)) {
            dev = rt->dst.dev;
            ip_rt_put(rt);
        }
    }
    if (dev) {
        imr->imr_ifindex = dev->ifindex;
        idev = __in_dev_get_rtnl(dev);
    }
    return idev;
}

imr->imr_ifindex is first used to search for the device. imr->imr_ifindex首先用于搜索设备。 If NOT found, imr->imr_address is used.如果没有找到, imr->imr_address使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM