Многоадресная передача на петлевом устройстве
Я хочу отправлять многоадресные пакеты 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
опция семантически отличается от версии UNIXIP_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 взят из моего сетевого интерфейса по умолчанию (т.е. интерфейса, который является моим шлюзом по умолчанию)
Скорее всего, так как вы не связали свою розетку. Что ты ожидал?