UDP组播接收端的绑定问题bind(),IP_ADD_MEMBERSHIP

UDP组播接收的代码如下:

struct sockaddr_in    localSock;
struct ip_mreq        group;
int                   sd;
int                   datalen;
char                  databuf[1024];

int main (int argc, char *argv[])
{
  sd = socket(AF_INET, SOCK_DGRAM, 0);
  if (sd < 0) {
    perror("opening datagram socket");
    exit(1);
  }
  
  memset((char *) &localSock, 0, sizeof(localSock));
  localSock.sin_family = AF_INET;
  localSock.sin_port = htons(5555);;
  localSock.sin_addr.s_addr  = INADDR_ANY; // or mcast_ip
  if (bind(sd, (struct sockaddr*)&localSock, sizeof(localSock))) {
    perror("binding datagram socket");
    close(sd);
    exit(1);
  }

  group.imr_multiaddr.s_addr = inet_addr("225.1.1.1"); //mcast_ip
  group.imr_interface.s_addr = inet_addr("9.5.1.1"); //local_ip
  if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                 (char *)&group, sizeof(group)) < 0) {
    perror("adding multicast group");
    close(sd);
    exit(1);
  }
  
  datalen = sizeof(databuf);
  if (read(sd, databuf, datalen) < 0) {
    perror("reading datagram message");
    close(sd);
    exit(1);
  }
}

socket有两个操作,一个是bind, 一个是setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,…)。

  1. bind()

TCP中bind()的意思是将该socket绑定到某个IP:PORT上,组播的意思是socket只接收该组播组的数据包。

如果这里绑定的是INADDR_ANY, 这个socket就讲接收到能听到的所有组播组IP相同端口的数据包, 即组播IP不同,端口相同时,组播串线的情况。

如果这里绑定的是某个具体组播组的IP, 这里内核向socket发送数据的时候就会过滤掉不是该组播组的数据。

据说在Windows中应该绑定物理网卡的IP地址, 而不是组播地址。

  1. IP_ADD_MEMBERSHIP

IP_ADD_MEMBERSHIP意思是加入组播组。 根据IGMP协议,主机将会向组播管理端发送一个报文,报告本机要加入某个交换机,交换机就会向相应的端口转发这个组播组的数据包。 group.imr_multiaddr.s_addr为组播组IP。
group.imr_interface.s_addr一般写要加入组播组主机的接口/网卡的 IP, 以确定收取哪一个子网的组播信息,会通过该接口接收组播包。如果设为INADDR_ANY(0.0.0.0),则使用默认的IPV4组播接口。
route -n 可以显示默认组播路由。

只有交换机的某个端口有对应组播组的接收host加入过组播组, 交换机才会向该端口组播数据包,否则默认是不不组播的。

补充:
IP_ADD_SOURCE_MEMBERSHIP可以指定组播源的IP, 即source_ip.
IP_MULTICAST_IF 可以设置组播发送端口

Ref:
https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzab6/x2multicast.htm

你可能感兴趣的:(C++,网络,udp,tcp/ip)