我有一个运行两个线程的小应用程序。
一个线程发送一个 UDP 多播数据包(到组 239.0.0.1),另一个线程读取同一个多播数据包。
当我使用 Visual Studio 在 Windows 上运行此应用程序时,它可以正常工作 - 数据包已成功发送和接收。我在 Wireshark 上看到了它。我还有一个嵌入式目标,此应用程序最终运行在该目标上,运行 VxWorks RTOS,并且它也可以在 VxWorks 上运行。
我在使用 WSL2 的 Linux 上尝试过。sendto() 成功,但 recvfrom() 失败。但是我在 Wireshark 上看到了数据包,并且 Wireshark 上没有报告任何错误。
我降级到 WSL1 并且它可以工作。
WSL2 中是否存在某些特定问题,可能会导致多播失败,但在 WSL1、Windows 和 VxWorks 上可以工作?如果我切换到单播,它可以在 WSL2 上运行。
以下是一些代码片段:
接收线程:
uint32_t ip_addr_mgrp;
uint32_t ip_addr_mifc;
inet_pton(AF_INET, (char*)"172.18.19.53", &ip_addr_mifc);
inet_pton(AF_INET, (char*)"239.0.0.1", &ip_addr_mgrp);
int fd = socket(AF_INET, SOCK_DGRAM, SOCKET_PROTOCOL);
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = ip_addr_mifc;
server_addr.sin_port = htons(45007);
bind(fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = ip_addr_mgrp;
mreq.imr_interface.s_addr = ip_addr_mifc;
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq));
// code to set to non-blocking
// Loop for reading
// Call select()
// Call FD_ISSET()
// Call recvfrom()
TX 线程:
uint32_t ip_addr_mgrp;
uint32_t ip_addr_mifc;
inet_pton(AF_INET, (char*)"172.18.19.53", &ip_addr_mifc);
inet_pton(AF_INET, (char*)"239.0.0.1", &ip_addr_mgrp);
int fd = socket(AF_INET, SOCK_DGRAM, SOCKET_PROTOCOL);
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = ip_addr_mgrp;
mreq.imr_interface.s_addr = ip_addr_mifc;
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq));
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&mreq.imr_interface.s_addr, sizeof(struct in_addr));
char loop = 1;
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&loop, sizeof(loop));
// code to set to non-blocking
// Loop for sending
// Call sendto() to 237.0.0.1:45007
在 Linux 上,如果套接字绑定到本地 IP 地址,则即使加入了多播组,它也无法接收多播流量。
正如评论中提到的,WSL1 是 Windows 系统调用上的 API 层,而 WSL2 是完整的 Linux 虚拟机。这就是为什么绑定到本地接口在 WSL1 上有效但在 WSL2 上无效的原因。
您可以通过将套接字绑定到
INADDR_ANY
或绑定到有问题的多播地址(在本例中为 239.0.0.1)来解决此问题。