多播接收器套接字中的重复数据包

以下MulticastReceiver实现中似乎存在错误。

在为和创建两个实例时,我在每个流中获取两个包。 有什么指针吗? 我的猜测是REUSEADDR?

class MulticastReceiverSocket { protected: const std::string listen_ip_; const int listen_port_; int socket_file_descriptor_; public: MulticastReceiverSocket ( const std::string & listen_ip, const int listen_port ) : listen_ip_ ( listen_ip ), listen_port_ ( listen_port ), socket_file_descriptor_ ( -1 ) { /* create socket to join multicast group on */ socket_file_descriptor_ = socket ( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); if ( socket_file_descriptor_ < 0 ) { exit(1); } /* set reuse port to on to allow multiple binds per host */ { int flag_on = 1; if ( ( setsockopt ( socket_file_descriptor_, SOL_SOCKET, SO_REUSEADDR, &flag_on, sizeof(flag_on) ) ) < 0 ) { exit(1); } } McastJoin ( ); { /* construct a multicast address structure */ struct sockaddr_in mcast_Addr; bzero ( &mcast_Addr, sizeof(mcast_Addr) ); mcast_Addr.sin_family = AF_INET; mcast_Addr.sin_addr.s_addr = htonl(INADDR_ANY); mcast_Addr.sin_port = htons ( listen_port_ ); /* bind to specified port onany interface */ if ( bind ( socket_file_descriptor_, (struct sockaddr *) &mcast_Addr, sizeof ( struct sockaddr_in ) ) < 0 ) { exit(1); } } } void McastJoin ( ) { /* construct an IGMP join request structure */ struct ip_mreq mc_req; inet_pton ( AF_INET, listen_ip_.c_str(), &(mc_req.imr_multiaddr.s_addr) ); mc_req.imr_interface.s_addr = htonl(INADDR_ANY); /* send an ADD MEMBERSHIP message via setsockopt */ if ( ( setsockopt ( socket_file_descriptor_, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*) &mc_req, sizeof(mc_req))) < 0) { printf ("setsockopt() failed in IP_ADD_MEMBERSHIP %s\n", listen_ip_.c_str() ); exit(1); } } inline int ReadN ( const unsigned int _len_, void * _dest_ ) { if ( socket_file_descriptor_ != -1 ) { return recvfrom ( socket_file_descriptor_, _dest_, _len_, 0, NULL, NULL ); } return -1; } 

请告知,当然,请指出可以进行的任何改进和优化。

您可以采取的一种方法是聪明地了解如何加入组,因此不是创建套接字,而是绑定(使用REUSEADDR)然后为每对ip,端口加入组,只构造一个套接字并绑定到给定的port,然后在同一个套接字上发出多个IGMP连接。

即在您的情况下,只创建一个套接字,每个端口绑定一次,但您加入多个组。 唯一的区别是,当您发出读取调用时,您将从一个或另一个组中获取数据包,并且您需要在数据包中包含足够的数据以便区分。

更换

 mcast_Addr.sin_addr.s_addr = htonl(INADDR_ANY); 

 mcast_Addr.sin_addr.s_addr = inet_addr (mc_addr_str); 

这对我(linux)有帮助,对于每个应用程序,我从一个端口上的单独mcast组接收单独的mcast流。

你也可以看看VLC播放器的来源,它在一个端口上显示来自不同mcast组的许多mcast iptv频道,但我不知道它是如何分配频道的。

我猜这是因为有多个接口(你在INADDR_ANY上加入了这个组)。 尝试指定确切的界面。 通过ioctl(2)SIOCGIFADDR获取接口地址。 检查您在netstat -ng哪个界面上加入了哪些组。

这是Linux路由的一个特性 ,每个会话都需要一个唯一的端口/组播组,只要端口匹配,Linux就会转发任何东西,例如广播数据包。 令人惊讶的是,Windows没有这种症状,这可能是因为它的速度较慢。

许多商业中间件包强制执行此兼容性要求,例如TIBCO的Rendezvous不允许重用相同的端口或组。

您是否尝试过关闭环回? 我发现如果我有一个合理的TTL,至少在使用SO_REUSEPORT时,不需要回送来获得单个TTL:

 int sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); if( sock < 0 ) exit( -11 ); int on = true; if( setsockopt ( sock, SOL_SOCKET, SO_REUSEPORT, & on, sizeof( on ) ) < 0 ) exit( -12 ); int off = 0; if ( setsockopt ( sock, IPPROTO_IP, IP_MULTICAST_LOOP, & off, sizeof( off ) ) < 0 ) exit( -13 ); int ttl = 3; if ( setsockopt ( sock, IPPROTO_IP, IP_MULTICAST_TTL, & ttl, sizeof( ttl ) ) < 0 ) exit( -14 ); 

如果我打开环回 - 默认情况下 - 我也得到双包。