以下MulticastReceiver实现中似乎存在错误。
为< 224.0.25.46,13001>创建两个实例时和< 224.0.25.172,13001&gt ;,我在每个流中得到每个数据包两次。有什么指针吗?我的猜测是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;
}
请提供建议,当然,请指出可以进行的任何改进和优化。
答案 0 :(得分:3)
替换
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频道,但我不知道它是如何分配频道的。
答案 1 :(得分:1)
我猜这是因为有多个界面(你加入INADDR_ANY
上的小组)。尝试指定确切的界面。通过ioctl(2)
SIOCGIFADDR
获取接口地址。检查您加入的哪些群组与netstat -ng
的界面。
答案 2 :(得分:1)
您可以采取的一种方法是聪明地了解如何加入组,因此不是创建套接字,绑定(使用REUSEADDR)然后为每对ip,端口加入组,只构造一个套接字并绑定到给定端口,然后在同一个套接字上发出多个IGMP连接。
即。在您的情况下,只创建一个套接字,每个端口绑定一次,但您加入多个组。唯一的区别是,当您发出读取呼叫时,您将从一个或另一个组中获取数据包,并且您需要在数据包中包含足够的数据以便区分。
答案 3 :(得分:1)
这是Linux路由的功能,每个会话都需要一个唯一的端口/组播组,只要端口匹配,Linux就会转发任何内容,例如广播数据包。 Windows令人惊讶地没有这种症状,这可能是因为它的速度较慢。
许多商业中间件包强制执行此兼容性要求,例如TIBCO的Rendezvous不允许重用相同的端口或组。
答案 4 :(得分:1)
您是否尝试过关闭环回?我发现如果我有一个合理的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 );
如果我打开环回 - 默认情况下 - 我也得到双包。