c - 2个用户空间程序在tun上使用多播

标签 c ubuntu-14.04 multicast qemu yocto

我仍在为 linux 进行网络编程,如果您觉得它含糊或不正确,请随时澄清我的理解。

查询:

我使用类似于 core-image-minimal 的 yocto 项目烘焙了一个 Linux 镜像。这部分与查询无关。我使用 QEMU 模拟器启动此镜像,当启动 QEMU 时,它会创建一个名为 tap0 的 sudo 接口(interface)。 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 发送的消息。

更进一步,

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

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

最佳答案

您的理解是正确的,您只需要解决两个问题:

  • 如果您在 INADDR_ANY 上绑定(bind),您将阻止所有其他地址(包括多播)的端口,除非您使用 REUSEADDR。您的 INADDR_ANY 绑定(bind)套接字也将接收它阻止访问的多播,除了:

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

模拟您当前的示例:

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

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并做成员(member)。所以阻塞套接字的代码可能是其他需要修改的代码才能像Qemu。

关于c - 2个用户空间程序在tun上使用多播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39186913/

相关文章:

子进程通过管道发送一个数字,然后等待

c - const 字符串动态数组的正确类型

c - Strsep,进一步解析 CSV 输入

ubuntu-14.04 - Puppet 4.x 可以安装在 Ubuntu 14 上吗?

C - 字符串被函数无意中更改

amazon-web-services - 在同一区域的两个 EC2 实例之间传输文件

laravel - 如何为 Vagrant 安装手动下载的 .box

c++ - 组播接收程序优化

tcp - 我可以为 TCP 使用广播或多播吗?

python - 为什么在同一端口上但来自不同组的多播消息会合并在一起?