There seems to be a bug in the following MulticastReceiver implementation.
On creating two instances for <224.0.25.46,13001> and <224.0.25.172,13001>, I get each packet twice in each stream. Any pointers ? My guess is 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;
}
Please advise, and of course, please point out any improvements, optimizations that can be made.
It's a feature of Linux routing, you need a unique port/multicast group for each session, Linux will forward on anything as long as the port matches, for example broadcast packets too. Windows surprisingly doesn't have this symptom, which is presumably why it is slower.
Many commercial middleware packages enforce this requirement for compatibility, for example TIBCO's Rendezvous will not permit reusing of the same port or group.
Have you tried just turning loopback off? I find that if I have a reasonable TTL, no loopback is required to get a single, at least when using SO_REUSEPORT:
If I leave loopback turned on--as it is by default--I get double packets too.
One approach you can take is to be smart about how you join the groups, so rather than create a socket, bind (with REUSEADDR) and then join group for each pair of ip, port, only construct a single socket and bind to a given port, and then issue multiple IGMP joins on the same socket.
i.e. in your case, only one socket is created, you bind once per port, but you join multiple groups. The only difference is that when you issue the read call, you will get a packet from one or the other group and you need to have enough data in the packet to allow your to distinguish.
Replace
with
it's help for me (linux), for each application i receive separate mcast stream from separate mcast group on one port.
Also you can look into VLC player source, it show many mcast iptv channel from different mcast group on one port, but i dont know, how it separetes channel.
I'm guessing this is because of multiple interfaces (you join the group on
INADDR_ANY
). Try specifying exact interface. Get the interface address viaioctl(2)
withSIOCGIFADDR
. Check what groups you joined on what interface withnetstat -ng
.