使用多播

时间:2016-08-28 00:14:42

标签: c ubuntu-14.04 multicast qemu yocto

我仍在使用Linux的网络编程,如果你觉得它模糊或不正确,请随时清楚我的理解。

查询:

我使用yocto项目烘焙了一个Linux图像,类似于core-image-minimal。这部分与查询无关。我使用QEMU模拟器启动此映像,当启动QEMU时,它会创建名为tap0的sudo接口。 QEMU的IP为192.168.7.2,tap0我的IP为192.168.7.1。

现在我有另一个用简单的C编写的用户空间程序,它试图监听QEMU程序(节点)发送的任何内容。所以,我使用了类似的片段:

if ( (fd = open("/dev/net/tun",O_RDWR)) < 0) PERROR("open");

memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = TUNMODE;
strncpy(ifr.ifr_name, "w-tap%d", IFNAMSIZ);
if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) PERROR("ioctl");

printf("Allocated interface %s. Configure and use it\n", ifr.ifr_name);

s = socket(PF_INET, SOCK_DGRAM, 0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(PORT);
if ( bind(s,(struct sockaddr *)&sin, sizeof(sin)) < 0) PERROR("bind");

fromlen = sizeof(from);
while(1) {
    l = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&from, &fromlen);
    //print the data etc
}

现在如果我用sudo ./tun_proxy 1534启动这个C代码,我就能听到192.168.7.2发送的这个端口上的消息。

此外,

我使用附加选项-net socket,mcast=224.244.224.245:30490启动QEMU,因为烘焙映像中有一个小程序,用于在多播组和端口上发送一些广播消息。此外,我应该能够在以前的tun_proxy应用程序上收听这些消息。我甚至创建了一个新的线程,它尝试监听多播组,但我收到错误消息“已在使用中”

我的理解究竟在哪里错了?我只需要2个用户空间程序,其中一个是通过多播消息进行通信的QEMU。

1 个答案:

答案 0 :(得分:1)

您的理解是合理的,您只需解决两个问题:

  • 如果您绑定INADDR_ANY,则除非使用REUSEADDR,否则您将阻止所有其他地址(包括多播)的端口。您的INADDR_ANY绑定套接字也将接收阻止访问的多播,但以下情况除外:

  • “主机”上的某个套接字需要使用IP_ADD_MEMBERSHIP,其中成员请求与任何套接字将接收多播流量之前的流量匹配。

模拟您当前的示例:

作为一个等效但相当奇怪的例子,shell1等同于你的监听器,shell2表明看似无关的套接字的ip-add-membership(但对于正确的地址和所有接口)会导致它接收流量:

shell1$ socat UDP-RECVFROM:30490,bind=0.0.0.0 EXEC:date

shell2$ echo hi | socat UDP-DATAGRAM:224.244.224.245:30490 STDIO
shell1$ (socat is still waiting for a packet)

shell2-add-membership$ socat UDP-RECVFROM:1044,reuseaddr,bind=127.0.0.1,ip-add-membership=224.244.224.245:0.0.0.0 EXEC:date&
       [1] 16003 
shell2$ echo hi | socat UDP-DATAGRAM:224.244.224.245:30490 STDIO
       Thu Sep  1 00:16:28 CEST 2016
shell1$ (socat now exits cleanly)

修复多播:

因此要运行2个以上的客户端,正确的方法是:

shellclient1$ socat UDP-RECVFROM:30490,bind=0.0.0.0,reuseaddr,ip-add-membership=224.244.224.245:0.0.0.0 EXEC:date
shellclient2$ socat UDP-RECVFROM:30490,bind=0.0.0.0,reuseaddr EXEC:date
...
shellclientn$ socat UDP-RECVFROM:30490,bind=0.0.0.0,reuseaddr EXEC:date


shell2$ echo hi | socat UDP-DATAGRAM:224.244.224.245:30490 STDIO
       Thu Sep  1 00:16:28 CEST 2016
       ...

请注意,所有必须使用SO_REUSEADDR,但只有一个必须添加成员资格。

Qemu's socket network uses SO_REUSEADDR并拥有会员资格。所以阻塞套接字的代码可能是需要修改为Qemu的其他代码。