C - 选择UDP /组播套接字的接口

时间:2012-10-01 21:07:12

标签: c sockets interface udp multicast

我正在尝试修改multicast listener / sender example以使用 INADDR_ANY 宏将UDP /多播套接字绑定到特定接口而

我拥有接口的IPv4地址。 我尝试了以下方法,但套接字没有收到任何UDP(单播,广播,多播)数据包。

struct sockaddr_in addr;
int fd, nbytes;
socklen_t  addrlen;
struct ip_mreq mreq;

// my_ipv4Addr equals current IP as String, e.g. "89.89.89.89"

// create what looks like an ordinary UDP socket */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    perror("socket");
    exit(1);
}

// set up addresses
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
// [-]    addr.sin_addr.s_addr = htonl(INADDR_ANY); 
addr.sin_addr.s_addr = inet_addr(my_ipv4Addr); 
addr.sin_port = htons(port);

// bind socket
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    perror("bind");
    exit(1);
}

// use setsockopt() to request that the kernel join a multicast group
mreq.imr_multiaddr.s_addr = inet_addr(group);
// [-]    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.imr_interface.s_addr = inet_addr(my_ipv4Addr);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))< 0) {
    perror("setsockopt");
    exit(1);
}

编辑:

让我解释一下我的计划的目的。 我正在编写一个小工具,它将检查网络是否支持广播/多播。因此,我拥有一个带有两个接口的系统,并通过Interface1发送一个多播数据包并尝试通过Interface2接收它。但是:数据包应通过网络, loopack设备。

我们的想法是使用:

阻止thread1 / interface1上的多播环回
u_char loop = 0;
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));

并在thread2 / interface 2上侦听特定于接口的内容。 Tcpdump显示数据包已到达,但在我的配置上面被丢弃。

4 个答案:

答案 0 :(得分:7)


    的 addr.sin_addr.s_addr=inet_addr(my_ipv4Addr);
    的 bind(sockfd,(SA*)&addr,sizeof(addr));
您只能将数据包发送到多播组,
但你不能收回任何数据包,即使是那些从'my_ipv4Addr'发出的数据包。

所以 addr.sin_addr.s_addr 必须 htonl(INADDR_ANY)


    的 mreq.imr_interface.s_addr=inet_addr(my_ipv4Addr);
您可以从多播组中收集所有数据包,
但它发送带有默认接口的数据包(可能是eth0),
不是你指定的那个(如eth1) 所以这没有效果。


    的 setsockopt(sockfd,SOL_SOCKET,SO_BINDTODEVICE,ETH1,strlen(ETH1));
你可以通过接口ETH1发送数据包,
但你只能从与ETH1相关联的ip发送出来的数据包,
你不能从其他客户收回任何数据包。


    的 mreq.imr_interface.s_addr=inet_addr(my_ipv4Addr);
    的 setsockopt(sockfd,IPPROTO_IP,IP_MULTICAST_IF,&mreq.imr_interface,sizeof(struct in_addr);
您可以通过与my_ipv4addr相关联的接口发送数据包,
您也可以从多播组中的任何客户端收回任何数据包。

答案 1 :(得分:4)

绑定套接字以接收多播流量时,如果绑定到本地地址,则可以防止在非Windows系统上接收多播数据包。

当我发布UFTP版本3.6并具有绑定到特定地址的功能时,我首先发现了这一点。 Windows处理它很好,但在Linux系统上,应用程序没有收到多播数据包。我不得不在下一个版本中删除该功能。

请注意,您可以直接绑定到多播地址:

addr.sin_addr.s_addr = inet_addr(group);

在这种情况下,您将仅接收该套接字上该多播地址的流量。但是,您仍然需要加入特定接口上的多播组才能接收。

如果您打算在同一个套接字上接收来自多个多播地址的数据,则需要绑定到INADDR_ANY

答案 2 :(得分:4)

bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY); 
//addr.sin_addr.s_addr = inet_addr(my_ipv4Addr); 
addr.sin_port = htons(port);

mreq.imr_multiaddr.s_addr = inet_addr(group);
// [-]    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.imr_interface.s_addr = inet_addr(my_ipv4Addr);

您只需像我一样编辑代码。

答案 3 :(得分:0)

要么为了理解而简化代码,要么我错过了一些东西,

这是结构

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 */
};

ip man page - IP_ADD_MEMBERSHIP

但你指的是

mreq.imr_interface.s_addr = inet_addr(my_ipv4Addr);

什么是 imr_interface ?它编译吗?

如果您刚刚编写了上面的名称以获得更好的可读性,您是否尝试将接口索引(即imr_ifindex)填充到要附加到的特定接口。

我的猜测是,如果你离开imrr_address并仅分配接口索引,它应绑定到该接口并接收数据包。看看是否有帮助。