繁体   English   中英

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

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

我需要使用相同的端口监听2个不同的组播组。 Program A将从230.0.0.1Program B230.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()...

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

如果你改变了

in_addr.sin_addr.s_addr = htonl(INADDR_ANY);

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

你可以获得更多的成功。

(如果你改变你的程序使用getaddrinfo() ,你可以使它面向未来。)

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

这里发布的手册页:

如果套接字sockfd的类型为SOCK_DGRAM,则addr是默认情况下发送数据报的地址, 以及接收数据报的唯一地址。

套接字代码的问题是“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函数

这里调用setsockopt调用的更多代码示例(查找关于如何使用IP地址调用与IP_PKTINFO的函数“EnablePktInfo”)。 还包含IPV6和BSD的扩展。

(来自在同一端口上接收多个多播源的 答案 - C,Linux

ip(7)联机帮助页描述了一种可能的解决方案:

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");
}

暂无
暂无

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

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