C - 选择 UDP/多播套接字接口

问题描述 投票:0回答:4

我正在尝试修改多播侦听器/发送器示例以将UDP/多播套接字绑定到特定接口,并且使用INADDR_ANY宏。

我拥有接口的 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);
}

编辑:

让我解释一下我的程序的目的。 我正在编写一个小工具,它将检查网络是否支持广播/多播。因此我拥有一个具有两个接口的系统,并通过接口1发送多播数据包并尝试使用接口2接收它。但是:数据包应通过网络,而不是环路设备。 这个想法是通过以下方式阻止线程1/接口1上的多播环回:

u_char loop = 0; setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));

并监听线程2/接口2特定接口。 Tcpdump 显示数据包已到达,但在我上面的配置中被丢弃。

c sockets interface udp multicast
4个回答
14
投票

addr.sin_addr.s_addr=inet_addr(my_ipv4Addr); bind(sockfd,(SA*)&addr,sizeof(addr));

您只能向多播组发送数据包,
但你
不能

recv()任何数据包,即使是那些从

my_ipv4Addr
发出的数据包。所以
addr.sin_addr.s_addr
一定是
htonl(INADDR_ANY)

mreq.imr_interface.s_addr=inet_addr(my_ipv4Addr);

您可以
recv()

来自多播组的所有数据包, 但它使用默认接口(例如

eth0
)发送数据包,而不是您指定的接口(例如
eth1
)。 所以这没有效果。
setsockopt(sockfd,SOL_SOCKET,SO_BINDTODEVICE,ETH1,strlen(ETH1));

可以通过接口

ETH1
向外发送数据包,
但您只能从与 
recv()

关联的 IP 发出

ETH1
数据包。您
不能
recv()
来自其他客户端的任何数据包。
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
关联的接口发送数据包。您还可以
recv()

来自多播组中任何客户端的任何数据包。

    
绑定用于接收多播流量的套接字时,如果绑定到本地地址,则会阻止在非 Windows 系统上接收多播数据包。


5
投票
UFTP

时,它具有绑定到特定地址的功能。 Windows 可以很好地处理它,但在 Linux 系统上,应用程序无法接收多播数据包。 我必须在下一个版本中删除该功能。

请注意,您可以直接绑定到多播地址: addr.sin_addr.s_addr = inet_addr(group);

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

如果您计划在同一套接字上从多个多播地址接收数据,那么您需要绑定到 
INADDR_ANY

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);


4
投票

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


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 手册页 - IP_ADD_MEMBERSHIP


但你指的是 mreq.imr_interface.s_addr = inet_addr(my_ipv4Addr);

什么是

imr_interface
?编译通过了吗?

如果您只是为了更好的可读性而写了上面的名称,您是否尝试过将接口索引(即 imr_ifindex)填充到您想要附加到的特定接口。 我的猜测是,如果您保留 imrr_address 并仅分配接口索引,它应该绑定到该接口并接收数据包。看看是否有帮助。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.