Tenho um pequeno aplicativo que executa dois threads.
Um thread envia um pacote multicast UDP (para o grupo 239.0.0.1) e o outro lê o mesmo pacote multicast.
Quando executo isso no aplicativo no Windows usando o Visual Studio, funciona - o pacote é enviado e recebido com sucesso. Vejo isso no Wireshark. Também tenho um alvo incorporado onde esse aplicativo finalmente roda, executando o VxWorks RTOS, e funciona no VxWorks também.
Eu tentei no Linux usando WSL2. O sendto() é bem-sucedido, mas o recvfrom() falha. No entanto, eu vejo o pacote no Wireshark, e não há erros relatados no Wireshark.
Fiz o downgrade para WSL1 e funciona.
Há algo especÃfico para WSL2 que pode fazer com que o multicast falhe, mas funcione em WSL1, Windows e VxWorks? Se eu mudar para unicast, funciona em WSL2.
Aqui estão alguns trechos de código:
Tópico de recebimento:
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()
Tópico 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
No Linux, se um soquete estiver vinculado a um endereço IP local, ele não poderá receber tráfego multicast, mesmo que o grupo multicast esteja unido.
Conforme mencionado nos comentários, WSL1 é uma camada de API sobre as syscalls do Windows, enquanto WSL2 é uma máquina virtual Linux completa. É por isso que vincular a uma interface local funciona em WSL1, mas não em WSL2.
Você pode corrigir isso vinculando o soquete
INADDR_ANY
ao endereço multicast em questão (239.0.0.1 neste caso).