Многоадресная передача на петлевом устройстве

Я хочу отправлять многоадресные пакеты UDP на адрес обратной связи и получать то же самое в другом приложении. Все тесты сделаны на Fedora Core 17 Linux.

Идея состоит в том, чтобы получить видеопоток через RTSP/HTTP или любой другой сетевой протокол и многоадресно передать его по адресу обратной связи, чтобы я мог использовать VLC для воспроизведения потока с использованием многоадресного адреса. Оставляя в стороне другие битрейты и контролируемые проблемы многоадресной рассылки, я попытался прочитать один видеофайл и многоадресную рассылку на устройстве обратной связи. Но когда попытался сыграть то же самое на VLC, это не сработало. Я могу видеть передачу пакетов в wireshark, но src ip взят из моего сетевого интерфейса по умолчанию (то есть интерфейса, который является моим шлюзом по умолчанию)

Я уже попробовал следующие команды

sudo ifconfig lo multicast
sudo ip route add 239.252.10.10 dev lo

Любое предложение в этом отношении было бы очень полезно.

Код тестовой программы, вставленный ниже

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>


    #define MULTICAST_ADDRESS "239.252.10.10"
    #define UDP_PORT 1234
    #define INTERFACE_IP    "127.0.0.1"
    #define MTU 1474
    #define DATA_BUFFER_SIZE  (1024*1024)

    static int  socket_init(char *intf_ip) {
    int sd;
    struct in_addr localInterface;

      sd = socket (AF_INET, SOCK_DGRAM, 0);
      if (sd < 0) {
          perror ("Opening datagram socket error");
          return -1;
      }
      else
        printf ("Opening the datagram socket...OK.\n");

      localInterface.s_addr = inet_addr (intf_ip);

      if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char *) &localInterface,sizeof (localInterface)) < 0){
          perror ("Setting local interface error");
          close(sd);
          return -1;
      }
      else
        printf ("Setting the local interface...OK\n");
    #if 1
        char loopch = 1;

        if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopch, sizeof(loopch)) < 0){
        perror("Setting IP_MULTICAST_LOOP error");
        close(sd);
        return -1;
        }
        else
        printf("Enabling the loopback...OK.\n");
    #endif
      return sd;

    }


    static int transmit_packet(int sd, char *databuf, int size,char *ip, unsigned short port){

    struct sockaddr_in groupSock;
    int len,datalen,rc;

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

      groupSock.sin_family = AF_INET;

      groupSock.sin_addr.s_addr = inet_addr (ip);

      groupSock.sin_port = htons (port);

      len=0;
      datalen = MTU;
      if(size < MTU)
        datalen = size;

      while(len < size){
        rc = sendto(sd, databuf, datalen, 0, (struct sockaddr *) &groupSock,sizeof (groupSock));
        if(rc <0){
          perror ("Sending datagram message error");
          return -1;
        }
        usleep(10000);
        len += rc;
      }
      return len;
    }

    static int transmit_file(char *filepath, char *dstip, char *srcip,unsigned short port) {
    FILE *fp;
    int sd,rc;
    char *databuf;


        fp = fopen(filepath, "r");
        if(!fp) {
        printf("transmit_file : no such file or directory %s \n",filepath);
        return -1;
        }
        sd = socket_init(srcip);
        if(sd < 0) {
        printf("Socket initialization failed \n");
        fclose(fp);
        return -1;
        }
        databuf = (char*) malloc(sizeof(char)*DATA_BUFFER_SIZE);
        if(!databuf) {
        printf("Unable to allocate databuf\n");
        close(sd);fclose(fp);
        return -1;
        }
        while(!feof(fp)){
        rc = fread(databuf,1,DATA_BUFFER_SIZE,fp);
        if(rc<= 0) {
            printf("read failed or EOF reached\n");
            break;
        }           
        if(transmit_packet(sd,databuf,rc,dstip,port) <0)
            printf("Transmit failed\n");    
        }
        close(sd);fclose(fp);
        free(databuf);
        return 0;
    }

    int main(int argc, char *argv[]){

       if(argc != 3){
        printf("%s <filename> <ip>\n",argv[0]);
        return -1;
       }
       transmit_file(argv[1],argv[2],INTERFACE_IP,UDP_PORT);
       return 0;
    }

2 ответа

Вы можете использовать многоадресную передачу при обратной связи, но вы должны добавить новый маршрут, потому что ваша ОС по умолчанию использует внешний интерфейс по умолчанию для многоадресной рассылки. Также многоадресная передача может быть отключена по умолчанию при обратной связи. В Linux вы можете изменить это с помощью этой команды:

route add -net 224.0.0.0 netmask 240.0.0.0 dev lo
ifconfig lo multicast

Привязка или маршрутизация к устройству обратной связи необходима, если вы не хотите, чтобы многоадресный IP-трафик (например, сообщения IGMP) передавался по сети. Однако обычно это необходимо только в том случае, если в сети есть другие компьютеры, которые могут создавать помехи, используя ту же группу многоадресной рассылки.

Настоящая проблема заключается в том, что программы на одном и том же хосте получают многоадресные данные, отправленные друг другом (или, что эквивалентно, наличие сокетов в одной программе, получающих многоадресные данные, отправленные друг другом), когда они оба настроены на использование одной и той же группы многоадресной рассылки.

Это довольно частый вопрос, по которому много вопросов по Stackru, но они часто неправильно понимаются или плохо сформулированы. Трудно искать эту проблему конкретно в отношении поведения или стандартизации операционной системы.

На аппаратном уровне многоадресный трафик рассматривается как широковещательный, поскольку он не направляется обратно на физический порт, с которого он был отправлен, для предотвращения петель на уровне канала. Это означает, что операционная система отвечает за пересылку трафика в другие программы или сокеты на том же хосте, который присоединился к группе многоадресной рассылки, поскольку он не будет считан из интерфейса.

Это настроено по стандарту IP_MULTICAST_LOOPвариант, который лучше всего описан в статье MSDN IP Multicast (в архиве):

В настоящее время в большинстве реализаций многоадресной IP-рассылки используется набор вариантов сокетов, предложенных Стивом Дирингом Инженерной группе Интернета (IETF). Таким образом, доступны пять операций:

[...]

  • IP_MULTICAST_LOOP- Контролирует возврат многоадресного трафика.

[...]

Версия Winsock IP_MULTICAST_LOOP опция семантически отличается от версии UNIX IP_MULTICAST_LOOP вариант:

  • В Winsock IP_MULTICAST_LOOP опция применяется только к пути приема.
  • В версии UNIX IP_MULTICAST_LOOP опция применяется к пути отправки.

Например, включенные и выключенные приложения (которые легче [отслеживать], чем X и Y) присоединяются к одной и той же группе на одном интерфейсе; приложение ON устанавливаетIP_MULTICAST_LOOP опция включена, приложение ВЫКЛ устанавливает IP_MULTICAST_LOOPвариант выключен. Если ON и OFF являются приложениями Winsock, OFF можно отправить в ON, а ON не может отправить в OFF. Напротив, если ON и OFF являются приложениями UNIX, ON может отправлять в OFF, но OFF не может отправлять в ON.

Из того, что я прочитал, этот параметр может быть отключен по умолчанию в Windows и включен по умолчанию в Linux, но я сам не тестировал его.

В качестве важного примечания IP_MULTICAST_LOOP вариант полностью отличается от IPV6_MULTICAST_LOOP вариант, относящийся к Linux ip(7) а также ipv6(7) страницы руководства:

IP_MULTICAST_LOOP (начиная с Linux 1.2) Устанавливает или считывает логический целочисленный аргумент, который определяет, должны ли отправленные многоадресные пакеты возвращаться в локальные сокеты.

IPV6_MULTICAST_LOOP Контролируйте, видит ли сокет многоадресные пакеты, которые он [отправил] сам. Аргумент - это указатель на логическое значение.

IP_MULTICAST_LOOP позволяет получать многоадресный IP-трафик на разных сокетах на том же хосте, на котором он был отправлен. IPV6_MULTICAST_LOOP позволяет получать многоадресный трафик IPv6 на том же сокете, который он был отправлен, что обычно невозможно с IPv4.

Если у кого-то есть ссылки на официальные стандарты о предполагаемом поведении реализаций (RFC, стандарты IEEE POSIX и т. Д.), Опубликуйте их в комментариях или отредактируйте этот ответ.

Я хочу отправлять многоадресные пакеты UDP на адрес обратной связи

Остановись прямо там. Вы не можете сделать это. Это невозможно. Вы можете отправлять только многоадресные рассылки на многоадресные адреса. Ваш код не выполняет многоадресную рассылку, просто отправляет на 127.0.0.1.

Если вы отправляете только на локальный хост, почему вы вообще используете многоадресную рассылку? У вас есть несколько процессов прослушивания?

ip src взят из моего сетевого интерфейса по умолчанию (т.е. интерфейса, который является моим шлюзом по умолчанию)

Скорее всего, так как вы не связали свою розетку. Что ты ожидал?

Другие вопросы по тегам