简体   繁体   English

如何使两个多播套接字侦听具有相同端口的两个多播通道

[英]How to have two multicast sockets listen to two multicast channels with same port

I have broadly the following multicast socket code. 我大致具有以下多播套接字代码。 It works fine. 工作正常。 Now I need to join two multicast channels on the same machine like 224.10.13.18 - 55001 224.10.13.34 - 55001 现在我需要在同一台机器上加入两个多播通道,例如224.10.13.18-55001 224.10.13.34-55001

and depending on which ip address it came from, I need to treat the message differently. 并且取决于它来自哪个IP地址,我需要对消息进行不同的处理。

The question is to how to use create two sockets for multicast channels where the port values are same, such that each socket only returns read on data that is sent to that channel. 问题是如何为端口值相同的多播通道使用创建两个套接字,以便每个套接字仅返回对发送到该通道的数据的读取。

  /* create socket to join multicast group on */
  socket_file_descriptor_ = socket ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
  if ( socket_file_descriptor_ < 0 ) 
    { // fprintf ( stderr, "cannot open socket \n");
      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 ) 
      { // fprintf ( stderr, "MulticastReceiverSocket setsockopt() SOL_SOCKET SO_REUSEADDR failed\n");
        exit(1);
      }
  } 

  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) 
  { // std::cerr << "setsockopt() failed in IP_ADD_MEMBERSHIP " << listen_ip_ << ": "<< listen_port_ << std::endl;
      exit(1);
  } 


  /* 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 ) 
  { // fprintf ( stderr, "%s cannot bind %s:%d \n", "MulticastReceiverSocket", listen_ip_.c_str(), listen_port_ ) ;
     exit(1);
  } 

You only need one socket for this. 您只需要一个插座即可。 If you set the IP_PKTINFO option on a call to setsockopt , you can use recvmsg to get a struct in_pktinfo , which will contain the destination IP address. 如果在对setsockopt的调用上设置IP_PKTINFO选项,则可以使用recvmsg获取struct in_pktinfo ,该struct in_pktinfo将包含目标IP地址。 Then you can choose how to process the packet based on that. 然后,您可以基于此选择如何处理数据包。

Borrowing from https://stackoverflow.com/a/5309155/1687119 (error checking removed for brevity): https://stackoverflow.com/a/5309155/1687119借用(为简洁起见,已删除错误检查):

// sock is bound AF_INET socket, usually SOCK_DGRAM
// include struct in_pktinfo in the message "ancilliary" control data
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt));
// the control data is dumped here
char cmbuf[0x100];
// the remote/source sockaddr is put here
struct sockaddr_in peeraddr;
// if you want access to the data you need to init the msg_iovec fields
struct msghdr mh = {
    .msg_name = &peeraddr,
    .msg_namelen = sizeof(peeraddr),
    .msg_control = cmbuf,
    .msg_controllen = sizeof(cmbuf),
};
recvmsg(sock, &mh, 0);
for ( // iterate through all the control headers
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh);
    cmsg != NULL;
    cmsg = CMSG_NXTHDR(&mh, cmsg))
{
    // ignore the control headers that don't match what we want
    if (cmsg->cmsg_level != IPPROTO_IP ||
        cmsg->cmsg_type != IP_PKTINFO)
    {
        continue;
    }
    struct in_pktinfo *pi = CMSG_DATA(cmsg);
    // at this point, peeraddr is the source sockaddr
    // pi->ipi_spec_dst is the destination in_addr
    // pi->ipi_addr is the receiving interface in_addr
}

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

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