【问题标题】:Duplicate packets in Multicast Receiver Socket [duplicate]多播接收器套接字中的重复数据包[重复]
【发布时间】:2011-06-24 19:55:22
【问题描述】:

以下 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;
}

请提出建议,当然,请指出可以进行的任何改进和优化。

【问题讨论】:

    标签: c++ c sockets multicast setsockopt


    【解决方案1】:

    替换

    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 频道,但我不知道它是如何分隔频道的。

    【讨论】:

    • @Stephan 和 Helius:这对我有用。非常感谢。
    【解决方案2】:

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

    即在您的情况下,只创建了一个套接字,每个端口绑定一次,但您加入了多个组。唯一的区别是,当你发出 read 调用时,你会从一个或另一个组中得到一个数据包,并且你需要在数据包中有足够的数据来让你区分。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        这是 Linux 路由的一个特性,每个会话都需要一个唯一的端口/多播组,只要端口匹配,Linux 就会转发任何东西,例如广播数据包。 Windows 出人意料地没有这种症状,这可能是它变慢的原因。

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

        【讨论】:

        • 和 对是同一数据包流的 A 馈送和 B 馈送,理想情况下希望处理来自无论它先到达哪个流。但是初始化 MulticastReceiverSocket 的两个实例并调用 ReadN ( ) 实际上在每个实例上交付了 4 个相同的数据包。
        • 从 linux 2.6.31 开始,有一个新功能允许禁用选项 IP_MULTICAST_ALL(参见answer
        【解决方案5】:

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

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

        如果我打开环回——默认情况下——我也会收到双包。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-30
          相关资源
          最近更新 更多