Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C在所有接口上侦听多播,在接收到的相同接口上响应_C_Sockets_Multicast - Fatal编程技术网

C在所有接口上侦听多播,在接收到的相同接口上响应

C在所有接口上侦听多播,在接收到的相同接口上响应,c,sockets,multicast,C,Sockets,Multicast,我试图在系统中的所有接口上侦听多播,但只在接收到多播数据包的接口上响应 我所做的是为每个接口创建一个套接字,然后问题就开始了 当我将接口绑定到INADDR_ANY时,它将接收所有接口的数据包,并发送默认数据包。若我将端口绑定到特定接口,它将不会接收多播数据包,但它将能够在正确的接口上发送它 我尝试过设置IP_添加_成员身份或IP_多播_IF之类的选项,但没有成功 我认为其他的选择是创建一个套接字来接收所有接口的所有ifs和发送方套接字,但在这种方法中,我不知道输入了哪个ifs数据包 简化的代码示

我试图在系统中的所有接口上侦听多播,但只在接收到多播数据包的接口上响应

我所做的是为每个接口创建一个套接字,然后问题就开始了

当我将接口绑定到INADDR_ANY时,它将接收所有接口的数据包,并发送默认数据包。若我将端口绑定到特定接口,它将不会接收多播数据包,但它将能够在正确的接口上发送它

我尝试过设置IP_添加_成员身份或IP_多播_IF之类的选项,但没有成功

我认为其他的选择是创建一个套接字来接收所有接口的所有ifs和发送方套接字,但在这种方法中,我不知道输入了哪个ifs数据包

简化的代码示例,没有错误处理和其他内容:

正在创建套接字:

//here i am looping over all interfaces from getifaddrs
struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr;

sockets[i] = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
setsockopt(sockets[i], SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);

mreq.imr_multiaddr.s_addr=inet_addr(MDNS_ADDRESS);
mreq.imr_interface.s_addr=pAddr->sin_addr.s_addr;

setsockopt(sockets[i], IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
setsockopt(sockets[i], IPPROTO_IP, IP_MULTICAST_IF, &pAddr, sizeof(struct in_addr));

memset(&my_addr, 0, sizeof(struct sockaddr_in));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY; //or pAddr->sin_addr.s_addr;
my_addr.sin_port = htons(port);

bind(sockets[i], (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
    perror("socket");
    exit(1);
}

if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) < 0) {
    perror("setsockopt");
    exit(1);
}

optval2 = 1;
if(setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &optval2, sizeof(optval2)) < 0) {
    perror("setsockopt");
    exit(1);
}

memset(&my_addr, 0, sizeof(struct sockaddr_in));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
my_addr.sin_port = htons(5353);

if (bind(sockfd, (struct sockaddr *)&my_addr,
    sizeof(struct sockaddr)) == -1) {
    perror("bind");
    exit(1);
}
接收和发送:

recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, (struct sockaddr *)&their_addr, &addr_len);

//do some magic and response (response should be a multicast too)

destination.sin_addr.s_addr = inet_addr(MULTICAST_ADDRESS);
destination.sin_family = AF_INET;
destination.sin_port = htons( port );
sendto(sockfd, buffer, len, 0, (struct sockaddr *)&destination, sizeof destination);

我想在工作中创建一些类似于MDN的东西,这样当数据包输入到特定接口上时,程序应该在相同的if上回答,并提供一些关于这个if的数据。它不应该在其他ifs上发送此消息,因为它可能与其他ifs无关,但它应该以多播方式发送,以便同一网络中的任何其他主机都将收到响应。

您应该只需要一个套接字即可

首先绑定到INADDR_ANY和您选择的端口。然后在每个要接收多播的接口上调用具有IP_ADD_成员身份的setsockopt。最后,如果要在接口上发送多播,请使用IP_MULTICAST_调用setsockopt。确保在每次通话中检查错误

int socket s;
struct sockaddr_in sin;
struct ip_mreq mreq;
struct in_addr out_addr;

bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr=htonl(INADDR_ANY);
sin.sin_port = htons(1044);   // or whatever port you listen on

if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
    perror("socket failed");
    exit(1);
}

if (bind(s, (struct sockaddr *)&sin, sizeof(sin))==-1) {
    perror("bind failed");
    exit(1);
}

// Do this in a loop for each interface
mreq.imr_multiaddr = inet_addr("230.4.4.1");     // your multicast address
mreq.imr_interface = inet_addr("192.168.1.1");   // your incoming interface IP
if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) == -1) {
    perror("Error joining multicast group");
    exit(1);
}

out_addr.s_addr = inet_addr("192.168.1.1");   // your outgoing interface IP
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *)&out_addr,sizeof(out_addr))== -1) {
    perror("Error setting outgoing interface");
    exit(1);
}

使用多播时,您应该始终绑定到INADDR_任意地址。否则会中断Linux系统上的多播。

最初,我接受了@dbush answer,因为它让我走上了正确的轨道。为了完整起见,我发布了更详细的答案,并且按照他的建议,我接受了自己的答案

在这里可以找到一些代码:

我可以用一个插座和设置IP_PKTINFO来完成所有这些

简化的代码示例,没有错误处理和其他内容:

正在创建套接字:

//here i am looping over all interfaces from getifaddrs
struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr;

sockets[i] = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
setsockopt(sockets[i], SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);

mreq.imr_multiaddr.s_addr=inet_addr(MDNS_ADDRESS);
mreq.imr_interface.s_addr=pAddr->sin_addr.s_addr;

setsockopt(sockets[i], IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
setsockopt(sockets[i], IPPROTO_IP, IP_MULTICAST_IF, &pAddr, sizeof(struct in_addr));

memset(&my_addr, 0, sizeof(struct sockaddr_in));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY; //or pAddr->sin_addr.s_addr;
my_addr.sin_port = htons(port);

bind(sockets[i], (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
    perror("socket");
    exit(1);
}

if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) < 0) {
    perror("setsockopt");
    exit(1);
}

optval2 = 1;
if(setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &optval2, sizeof(optval2)) < 0) {
    perror("setsockopt");
    exit(1);
}

memset(&my_addr, 0, sizeof(struct sockaddr_in));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
my_addr.sin_port = htons(5353);

if (bind(sockfd, (struct sockaddr *)&my_addr,
    sizeof(struct sockaddr)) == -1) {
    perror("bind");
    exit(1);
}

你可以发布代码吗?你使用哪个平台?Linux试图尽可能接近POSIX当你回应时,你基本上会使用默认的路由表,除非你选择一个特定的接口。在windows IP上,添加成员资格/IGMP请求也将只在一个界面上发送,但我不确定linux。使用route命令查看或操作routing table.thx,但我希望能够在不更改路由表的情况下指定传出接口。感谢您的回答,但使用单个套接字时,我不知道输入了哪个接口数据包,我希望在相同的if上发送响应。另一方面,我应该在每次响应之前更改IP_MULTICAST_吗?使用MULTICAST时,您应该始终绑定到INADDR_任意地址-您是否有来源来确认这一点?绑定到特定的多播组地址似乎不会导致任何不良行为。还有一条证据表明UNIX网络编程,第三版表明绑定到一个组地址是可取的,对不起,它不是英文的,如果你不理解语言,考虑使用自动翻译:@ Pavelkiiiko实际上,绑定到一个多播地址是有效的,假设您只希望接收来自单个多播GROUP的流量。你不能做的是绑定到一个特定的网络接口,而OP就是这么做的。如果您想要收听多个多播组或同时想要接收单播流量,则需要绑定到InAdr_ANY。这很有意义,谢谢。很高兴您自己能够找到这一点。我本来打算在IP_PKTINFO上发布一些信息,但我没有时间提前发布详细的更新。事实上,我认为这个答案应该是公认的答案。它直接回答了这个问题,而我的只是给出了一些提示,并且显示了您的良好研究。