无法使用 IPv6 进行多播

Unable to multicast using IPv6

这是发送方和接收方(组合)的代码。

int main (int argc, char *argv[]) {
  struct in6_addr localInterface;
  struct sockaddr_in6 groupSock;
  // socket descriptor for multicast
  int sd;

  char databuf[10];
  // length of message
  int datalen = sizeof(databuf);

  /* Create a datagram socket on which to send/receive. */
  sd = socket(AF_INET6, SOCK_DGRAM, 0);

  if(sd < 0) {
    perror("Opening datagram socket error");
    exit(1);
  }
  else {
    printf("Opening the datagram socket...OK.\n");
  }

  /* Enable SO_REUSEADDR to allow multiple instances of this */
  /* application to receive copies of the multicast datagrams. */
  {
    int reuse = 1;
    if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
      {
    perror("Setting SO_REUSEADDR error");
    close(sd);
    exit(1);
      }

    else {
      printf("Setting SO_REUSEADDR...OK.\n");
    }
  }

  /* Initialize the group sockaddr structure with a */
  memset((char *) &groupSock, 0, sizeof(groupSock));
  groupSock.sin6_family = AF_INET6;
  // address of the group
  // groupSock.sin6_addr = inet6_addr("ff5e::/16");
  inet_pton(AF_INET6, "ff5e::/16", &(groupSock.sin6_addr));

  groupSock.sin6_port = htons(4321);

  /* Set local interface for outbound multicast datagrams. */
  /* The IP address specified must be associated with a local, */
  /* multicast capable interface. */
  char *ip_address = argv[2];
  inet_pton (AF_INET6, ip_address, &(localInterface.s6_addr));

  memset((char *) &localInterface, 0, sizeof(localInterface));  

  int ifindex;
  ifindex = if_nametoindex ("eth5");
  printf ("ifindex is %d\n", ifindex);

  if(setsockopt(sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)))
    {
      perror("Setting local interface error");
      exit(1);
    }
  else {
    printf("Setting the local interface...OK\n");
  }

  // choice is 0 for sending and 1 for receiving
  int choice;
  sscanf (argv[1], "%d", &choice);

  // if sending
  if (choice == 0) {
    int i;
    for (i = 0; i < datalen-1; ++i) {
      databuf[i] = 'a';
    }
    databuf[i] = 0;

    if (sendto(sd, databuf, datalen, 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0) {
      printf ("Error in send\n");
    }

    else {
      printf ("Send okay!\n");
    }
  }

  // if receiving
  else if (choice == 1) {
    groupSock.sin6_addr = in6addr_any;
    if(bind(sd, (struct sockaddr*)&groupSock, sizeof(groupSock))) {
      perror("Binding datagram socket error");
      close(sd);
      exit(1);
    }

    else {
      printf("Binding datagram socket...OK.\n");
    }

    /* Join the multicast group ff5e::/16 on the local  */
    /* interface. Note that this IP_ADD_MEMBERSHIP option must be */
    /* called for each local interface over which the multicast */
    /* datagrams are to be received. */
    struct ipv6_mreq group;
    inet_pton (AF_INET6, "ff5e::", &(group.ipv6mr_multiaddr.s6_addr));

    // group.imr_interface.s6_addr = inet_addr(ip_address);
    group.ipv6mr_interface = ifindex;

    if(setsockopt(sd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0) {
      perror("Adding multicast group error");
      close(sd);
      exit(1);
    }

    else {
      printf("Adding multicast group...OK.\n");
    }

    if (read(sd, databuf, datalen) < 0) {
      perror("Error in read");
    }

    else {
      printf("Read Okay\n");
      printf ("Message is : %s\n", databuf);
    }
  }

}

如果发送方和接收方在不同的节点上,则接收方收不到消息(我已使用ping6 确认它们已连接)。我正在开发 Linux Ubuntu 14.04。使用 tcpdump 捕获 ipv6 数据包显示数据包未在发送方发送。有什么问题?

一个问题是您选择的 IPv6 多播地址不当。 FF5E:: 分解如下:

  • FF表示多播
  • 5是标志集(0101),这个值是一个无效的标志集。设置最高位意味着您有一个嵌入式 RP 地址,而您显然没有。为此,标志集必须是 7 (0111),然后遵循嵌入 RP 地址的所有规则。
  • E表示是全局作用域。

这个多播地址应该正确地丢弃在它遇到路由器的任何路径中。

请参阅 RFC 4291、3306 和 3956 以创建 IPv6 多播地址,包括标志和范围的含义。