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

时间:2011-12-12 20:01:26

标签: c linux udp multicast

我需要使用相同的端口侦听2个不同的组播组。 Program A将从230.0.0.1Program B收听230.0.0.2。两个组播组都使用相同的port 2000,我无法控制它。

当我运行程序时,我会在每个程序中收到两个组播流,即230.0.0.1230.0.0.2上广播的数据包。我怀疑问题是由于公共端口造成的。这是我用来订阅多播的代码:

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()...

如何在每个程序中过滤特定的多播组?

4 个答案:

答案 0 :(得分:4)

如果你改变了

in_addr.sin_addr.s_addr = htonl(INADDR_ANY);

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

你可以取得更大的成功。

(如果您将程序更改为使用getaddrinfo(),则可以使其面向未来。)

答案 1 :(得分:3)

“连接”可能就是你所需要的。通常,为了连接TCP套接字,手册页还建议它可以用于过滤掉来自其他地址的UDP数据包:

从发布的here手册页

  

如果套接字sockfd的类型为SOCK_DGRAM,那么addr就是地址   默认情况下发送哪些数据报,和唯一的地址   收到数据报。

答案 2 :(得分:2)

套接字代码的问题是“recvfrom”只会为您提供发送数据包的源地址。它不会告诉您数据包发送到的位置的IP地址。您希望能够检查UDP数据包的目标地址,以便过滤掉发送到您不感兴趣的多播IP地址的数据包。

您可以设置一个套接字选项,然后使用“recvmsg”而不是recv或recvfrom来获取发送数据包的目标IP地址。

1)将setsockopt与IP_PKTINFO一起使用,以便为在套接字上收到的数据获取传递到应用级别的目标IP地址。

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

2)使用recvmsg而不是recvfrom(或recv)来获取UDP数据包发送到的目标地址。我有一个名为“recvfromex”的辅助函数,它包装了recvmsg并镜像了recvfrom的功能 - 期望它有一个额外的参数供调用者获取数据包的目标IP。

发布有点大风 - 但你可以从我的github项目中查看我的C ++代码并获取你需要的东西。

查看recvfromex函数here

setsockopt调用here的更多代码示例(查找有关如何使用与IP_PKTINFO的setsockopt调用的函数“EnablePktInfo”)。还包含IPV6和BSD的扩展名。

答案 3 :(得分:1)

(来自answerReceving multiple multicast feeds on the same port - C, Linux

ip(7) manpage描述了一种可能的解决方案:

  

IP_MULTICAST_ALL(自Linux 2.6.31起)
                此选项可用于修改交付策略                 组播消息到绑定到通配符INADDR_ANY的套接字                 地址。参数是一个布尔整数(默认为1)。                 如果设置为1,套接字将接收来自所有的消息                 在整个系统上全局加入的组。                 否则,它将仅从组中传递消息                 已明确加入(例如通过                 IP_ADD_MEMBERSHIP选项)在这个特定的套接字上。

然后,您可以使用以下命令激活过滤器以接收已加入组的消息:

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