我希望将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;
}
答案 0 :(得分:17)
您可以在环回上使用多播,但您必须添加新路由,因为您的操作系统默认使用默认外部接口进行多播。还可以在环回时禁用多播。在linux上,您可以使用以下命令更改此信息:
route add -net 224.0.0.0 netmask 240.0.0.0 dev lo
ifconfig lo multicast
答案 1 :(得分:2)
如果您不想跨网络发送IP多播流量(例如IGMP消息),则必须绑定或路由到回送设备。但是,通常只有在网络上还有其他计算机可能会因使用同一多播组而受到干扰时,才需要这样做。
真正的问题是,当同一主机上的程序都配置为使用相同的程序时,它们会接收彼此发送的多播数据(或者等效地,使单个程序中的套接字接收彼此的多播数据)。多播组。
这是一个很常见的问题,上面有许多StackOverflow问题,但是它们常常被误解或措辞不佳。专门针对操作系统行为或标准化来搜索此问题很困难。
在硬件级别,多播流量被视为广播流量,因为它不会路由回到发送该端口的物理端口,以防止链路级环路。这意味着操作系统负责将流量转发到加入多播组的同一主机上的其他程序或套接字,因为不会从接口读取该流量。
这是由标准的IP_MULTICAST_LOOP
选项配置的,最好由IP Multicast MSDN article (archived)进行总结:
当前,大多数IP多播实现使用由Steve Deering向Internet工程任务组(IETF)提出的一组套接字选项。因此可以进行五种操作:
[...]
IP_MULTICAST_LOOP
-控制多播流量的环回。[...]
IP_MULTICAST_LOOP
选项的Winsock版本在语义上与IP_MULTICAST_LOOP
选项的UNIX版本不同:
- 在Winsock中,
IP_MULTICAST_LOOP
选项仅适用于接收路径。- 在UNIX版本中,
IP_MULTICAST_LOOP
选项适用于发送路径。例如,应用程序ON和OFF(比X和Y更容易跟踪)在同一接口上加入同一组;应用程序打开将
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标准等),请在注释中发布它们或编辑此答案。
答案 2 :(得分:0)
我希望将UDP组播数据包发送到环回地址
停在那儿。你不能这样做。不可能。您只能将多播发送到多播地址。您的代码不进行任何多播,只需发送到127.0.0.1。
如果您只是发送到本地主机,为什么要使用多播?你有多个听力过程吗?
src ip取自我的默认网络接口(即接口,这是我的默认网关)
很有可能,因为你没有绑定你的插座。你有什么期望?