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

use*_*602 15 c sockets udp interface multicast

我试图修改多播侦听器/发送器示例以将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);
}
Run Code Online (Sandbox Code Playgroud)

编辑:

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

想法是在thread1/interface1上阻止多播环回:

u_char loop = 0;
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
Run Code Online (Sandbox Code Playgroud)

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

PLA*_*PLA 7

与 只能发送数据包到多播组, 但你不能recv的任何数据包,甚至是那些来自'my_ipv4Addr送出去".
addr.sin_addr.s_addr=inet_addr(my_ipv4Addr);
bind(sockfd,(SA*)&addr,sizeof(addr));


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

与 你的recv从组播组中的所有数据包, 但它的默认界面(也许为eth0)来发送数据包, 不是你指定的(如eth1的). 所以这没有效果.
mreq.imr_interface.s_addr=inet_addr(my_ipv4Addr);




与 您可以通过eth1接口发送出去的数据包, 但你只能recv的数据包从与ETH1关联的IP发送出去, 你不能recv的其他客户端的任何数据包.
setsockopt(sockfd,SOL_SOCKET,SO_BINDTODEVICE,ETH1,strlen(ETH1));



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



dbu*_*ush 5

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

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

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

addr.sin_addr.s_addr = inet_addr(group);
Run Code Online (Sandbox Code Playgroud)

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

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


fkl*_*fkl 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 */
};
Run Code Online (Sandbox Code Playgroud)

ip 手册页 - IP_ADD_MEMBERSHIP

但你指的是

mreq.imr_interface.s_addr = inet_addr(my_ipv4Addr);
Run Code Online (Sandbox Code Playgroud)

什么是imr_interface?它能编译吗?

如果您只是为了更好的可读性而在上面写了名称,您是否尝试过将接口索引(即 imr_ifindex)填充到您想要附加到的特定接口。

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

  • `ip_mreqn` 是新结构,问题使用 `ip_mreq`,Linux 两者都支持。 (2认同)