【发布时间】:2012-09-22 18:20:03
【问题描述】:
我正在尝试修改 multicast listener / sender example 以将 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);
}
编辑:
让我解释一下我的程序的目的。 我正在编写一个小工具,它将检查网络是否支持广播/多播。 因此,我拥有一个具有两个接口的系统,并通过 Interface1 发送一个多播数据包并尝试使用 Interface2 接收它。但是:数据包应该通过网络,而不是环包设备。
这个想法是在 thread1/interface1 上阻止多播环回:
u_char loop = 0;
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
并监听 thread2/interface 2 特定接口。 Tcpdump 显示,数据包正在到达,但在我上面的配置中被丢弃。
【问题讨论】:
-
我认为您必须绑定到的不是 IP,而是绑定到设备,例如
setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 4) -
如果你让内核为你选择一个接口会发生什么?即使用
mreq.imr_interface.s_addr = htonl(INADDR_ANY); -
@Gene 正确。使用
setsockopt( ... SO_BINDTODEVICE ...)我可以将 UDP 套接字绑定到接口,但我如何明确地为多播执行此操作? @shinkou 设置为 INADDR_ANY(UDP 和多播订阅)不会改变套接字不接收数据包的事实。在我设置net.ipv4.{all,default,interfaces}.rp_filter = 0之前,数据包被作为火星人丢弃(在/var/log/syslog 中可见)。似乎与 Linux 相关,因为可以通过 tcpdump 在传出和传入接口上看到数据包。不过现在不知道... -
你的路由表是什么样的?当你运行你的监听器时
netstat -ng会说什么? -
您可能需要执行
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, ..)来控制数据包从哪个接口发送...
标签: c sockets interface udp multicast