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



我正在尝试修改多播侦听器/发送器示例,以便使用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);
}

编辑:

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

这个想法是阻止线程1/接口1上的多播环回:

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

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

使用
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关联的接口发送数据包,
还可以从多播组中的任何客户端接收任何数据包

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

你只需要像我一样编辑你的代码。

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

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

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

addr.sin_addr.s_addr = inet_addr(group);

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

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

要么是为了理解而简化了代码,要么是我遗漏了一些东西,

这是结构

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并只分配接口索引,它应该绑定到该接口并接收数据包。看看这是否有帮助。

最新更新