简体   繁体   English

UDP:为两个不同的多播流侦听同一端口

[英]UDP: Listening to the same port for two different multicast streams

I need to listen to 2 different multicast groups using the same port. 我需要使用相同的端口监听2个不同的组播组。 Program A will listen from 230.0.0.1 and Program B from 230.0.0.2 . Program A将从230.0.0.1Program B230.0.0.2 Both multicast groups use the same port 2000 and I have no control over it. 两个组播组都使用相同的port 2000 ,我无法控制它。

When I run my programs I receive both multicast streams in each program, that is both the data packets broadcasted on 230.0.0.1 and 230.0.0.2 . 当我运行我的程序时,我在每个程序中都收到两个组播流,即230.0.0.1230.0.0.2上广播的数据包。 I suspect the problem is due to the common port. 我怀疑问题是由于公共端口造成的。 This is the code I am using to subscribe to the multicast: 这是我用来订阅多播的代码:

if( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0 ) {
  perror("socket");
  return -1;
}

if( setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0 ) {
  perror("setsockopt SO_REUSEADDR");
  return -1;
}

memset(&in_addr, 0, sizeof(in_addr));
in_addr.sin_family = AF_INET;
in_addr.sin_addr.s_addr = htonl(INADDR_ANY);
in_addr.sin_port = htons(2000);
if( bind(sd, (struct sockaddr*)&in_addr, sizeof(in_addr)) < 0 ) {
  perror("bind");
  return -1;
}

memset(&req, 0, sizeof(req));
inet_aton(intfc_ip, &req.imr_interface);
inet_aton("230.0.0.1", &req.imr_multiaddr);
if( setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req, sizeof(req)) < 0 ) {
  perror("setsockopt IP_ADD_MEMBERSHIP");
  return -1;
}

recv()...

How can I filter a specific multicast group in each program? 如何在每个程序中过滤特定的多播组?

If you change 如果你改变了

in_addr.sin_addr.s_addr = htonl(INADDR_ANY);

to

inet_aton(<your wanted IP address>, &in_addr.sin_addr.s_addr);

you could have more success. 你可以获得更多的成功。

(And if you change your program to work with getaddrinfo() , you make it future-proof.) (如果你改变你的程序使用getaddrinfo() ,你可以使它面向未来。)

"connect" might be what you need after all. “连接”可能就是你所需要的。 Typically, for connecting TCP sockets, the man page also suggests that it can be used for filtering out UDP packets from other addresses: 通常,对于连接TCP套接字,手册页还建议它可用于过滤掉来自其他地址的UDP数据包:

From the man page posted here : 这里发布的手册页:

If the socket sockfd is of type SOCK_DGRAM then addr is the address to which datagrams are sent by default, and the only address from which datagrams are received. 如果套接字sockfd的类型为SOCK_DGRAM,则addr是默认情况下发送数据报的地址, 以及接收数据报的唯一地址。

The problem with socket code is that "recvfrom" will only give you the source address from where the packet was sent from. 套接字代码的问题是“recvfrom”只会为您提供发送数据包的源地址。 It doesn't tell you the IP address of where the packet was sent to. 它不会告诉您数据包发送到的位置的IP地址。 You want to be able to inspect the destination address of the UDP packet so you can filter out packets that were sent to multicast IP addresses you are not interested in. 您希望能够检查UDP数据包的目标地址,以便过滤掉发送到您不感兴趣的多播IP地址的数据包。

There is a socket option you can set followed by the use of "recvmsg" instead of recv or recvfrom to get the destination IP adddress the packet was sent to. 您可以设置一个套接字选项,然后使用“recvmsg”而不是recv或recvfrom来获取发送数据包的目标IP地址。

1) Use setsockopt with IP_PKTINFO to enable getting the destination IP address passed up to the app level for data received on the socket. 1)将setsockopt与IP_PKTINFO一起使用,以便为在套接字上接收的数据获取传递到应用级别的目标IP地址。

int enable = 1;
setsockopt(sock, IPPROTO_IP , IP_PKTINFO , &enable, sizeof(enable));

2) Use recvmsg instead of recvfrom (or recv) to get the destination address the UDP packet was sent to. 2)使用recvmsg而不是recvfrom(或recv)来获取UDP数据包发送到的目标地址。 I have a helper function called "recvfromex" that wraps recvmsg and mirrors the functionality of recvfrom - expect it has an extra parameter for the caller to get the destination IP of the packet. 我有一个名为“recvfromex”的辅助函数,它包装了recvmsg并镜像了recvfrom的功能 - 期望它有一个额外的参数供调用者获取数据包的目标IP。

It's a bit windy to post - but you can look at my C++ code from my github project and take what you need. 发布有点大风 - 但你可以从我的github项目中查看我的C ++代码并获取你需要的东西。

Look at the recvfromex function here 这里查看recvfromex函数

More code sample for the setsockopt call here (look for the function "EnablePktInfo" on how to use the setsockopt call with IP_PKTINFO). 这里调用setsockopt调用的更多代码示例(查找关于如何使用IP地址调用与IP_PKTINFO的函数“EnablePktInfo”)。 Also contains extensions for IPV6 and BSD. 还包含IPV6和BSD的扩展。

(from answer of Receving multiple multicast feeds on the same port - C, Linux ) (来自在同一端口上接收多个多播源的 答案 - C,Linux

The ip(7) manpage describe a possible solution : ip(7)联机帮助页描述了一种可能的解决方案:

IP_MULTICAST_ALL (since Linux 2.6.31) IP_MULTICAST_ALL(自Linux 2.6.31起)
This option can be used to modify the delivery policy of multicast messages to sockets bound to the wildcard INADDR_ANY address. 此选项可用于将组播消息的传递策略修改为绑定到通配符INADDR_ANY地址的套接字。 The argument is a boolean integer (defaults to 1). 参数是一个布尔整数(默认为1)。 If set to 1, the socket will receive messages from all the groups that have been joined globally on the whole system. 如果设置为1,则套接字将从整个系统上全局加入的所有组接收消息。 Otherwise, it will deliver messages only from the groups that have been explicitly joined (for example via the IP_ADD_MEMBERSHIP option) on this particular socket. 否则,它将仅从已在此特定套接字上显式连接的组(例如,通过IP_ADD_MEMBERSHIP选项)传递消息。

Then you can activate the filter to receive messages of joined groups using : 然后,您可以使用以下命令激活过滤器以接收已连接组的消息:

int mc_all = 0;
if ((setsockopt(sock, IPPROTO_IP, IP_MULTICAST_ALL, (void*) &mc_all, sizeof(mc_all))) < 0) {
    perror("setsockopt() failed");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM