Vários aplicativos usando o mesmo grupo multicast no mesmo host Windows

Vários aplicativos usando o mesmo grupo multicast no mesmo host Windows

Sou um engenheiro de software que projeta um software distribuído, no qual o procedimento de inicialização utiliza multicasting IP para descobrir seus pares. O software em si é distribuído como diferentes módulos executáveis ​​e, como tal, às vezes faz sentido executar vários módulos executáveis ​​no mesmo host. É aqui que começam os meus problemas, pois me parece que o Windows não é bom no gerenciamento de vários processos inscritos em um único grupo multicast.

Meu objetivo é poder escolher livremente em quais hosts eu inicio quais executáveis, e estes descobrirão todos os seus pares (seja no mesmo host ou em outros hosts) sem qualquer conhecimento predefinido.

Até agora, a solução de problemas indica que o problema é como o Windows lida com o cenário de vários processos inscritos nos mesmos grupos multicast, porque:

  1. Se o mesmo processo for usado para enviar e receber datagramas multicast na mesma máquina, ele funcionará conforme o esperado. O processo pode ser dividido em vários threads sem nenhum problema.

  2. Se eu executar processos diferentes de envio e recebimento, o processo de recebimento não receberá nada, apesar da mensagem de adesão ao grupo e de todos os datagramas aparecerem no Wireshark.

  3. O cenário descrito em 2 funciona se eu, antes de ouvir, também usar o mesmo soquete para enviar um pacote para o grupo multicast ao qual entrei. Em seguida, este último recebe datagramas multicast por um período de tempo não especificado, após o qual apenas para de receber datagramas (fica aguardando a chegada dos datagramas). Os datagramas são confirmados sendo enviados de/para a rede usando o Wireshark.

  4. Minhas últimas descobertas indicam que se eu enviar periodicamente uma mensagem multicast para o grupo no qual me inscrevo, recebo datagramas enviados para esse grupo multicast, também de outros processos no mesmo host.

O multicast IP, até onde eu entendo, define apenas a comunicação entreanfitriões, embora seja responsabilidade do sistema operacional redirecionar os pacotes recebidos para o local apropriadoaplicativo. Como os pacotes parecem sempre aparecer no Wireshark, mesmo que um aplicativo não os receba, parece que o Windows falha ao lidar com os pacotes recebidos, ou pelo menos entregá-los aos aplicativos apropriados.

Agradeço se alguém puder confirmar ou rejeitar meu raciocínio, bem como me indicar a direção certa sobre como resolver esse problema. O objetivo é permitir que vários aplicativos no mesmo host ingressem em um único canal de grupo multicast e também recebam mensagens sem a necessidade de enviar "lixo" também para o grupo multicast para que eles recebam dados (a solução alternativa descrita como número do ponto 4).

Estou usando Java para implementação e posso, se solicitado, postar um MWE aqui. Porém, temo que isso possa mudar o foco do cenário para a programação, o que não é a preocupação aqui (pelo que posso deduzir).

Responder1

O OP está pedindo um método para descobrir pares em uma rede sem conhecimento desses pares, de acordo comesta fonteO mDNS requer pelo menos conhecimento do nome do host de cada par.

Como resultado, o mDNS não é uma solução viável para este problema conforme descrito.

De acordo compara esta resposta, sobre multicast, o que você pediu é possível. Envolve o uso da opção de soquete SO_REUSEADDR. Quando você usa esta opção de soquete, ela permite que vários soquetes escutem na mesma combinação endereço:porta, desde que;

  1. O endereço é um endereço multicast; e
  2. SO_RESUSEADDR é definido em cada soquete que tenta se vincular à combinação endereço:porta.

No entanto, de acordo comesta resposta, você também pode precisar definir SO_BROADCAST em cada soquete, o que certamente não é intuitivo! Em meus próprios testes usando python no Windows, no entanto, NÃO precisei fazer isso, então não tenho certeza de quão legítima é essa resposta, menciono-a caso você fique preso, embora eu trate isso como potencialmente desatualizado, estou testando no Windows 10 no momento.

Aqui está um exemplo de código que testei e não produz erros. É parte de um teste automatizado que usa beacons para conectar um processo de trabalho a um processo de corretor. Este teste é aprovado quando executado em um único nó, ainda não o testei em vários nós

import socket, struct

MCAST_GRP = ''
MCAST_PORT = 1234

MULTICAST_TTL = 2

def create_beacon_listener():

    sock = socket.socket(
        socket.AF_INET,
        socket.SOCK_DGRAM,
        socket.IPPROTO_UDP
    )
    sock.setsockopt(
        socket.SOL_SOCKET,
        socket.SO_REUSEADDR,
        1
    )
    sock.setblocking(0)

    sock.bind(( MCAST_GRP, MCAST_PORT ))

    multicast_grp_req = struct.pack(
        "4sl",
        socket.inet_aton(MCAST_GRP),
        socket.INADDR_ANY
    )

    sock.setsockopt(
        socket.IPPROTO_IP,
        socket.IP_ADD_MEMBERSHIP,
        multicast_grp_req
    )
    
    return sock

O código acima retorna um soquete de escuta no endereço de grupo desejado MCAST_GRP e na porta MCAST_PORT. E sim, o MCAST_GRP está definido como uma string em branco, o que significa que você realmente escuta todos os grupos de endereços multicast. Esta parece ser uma limitação do Windows ou do meu conhecimento, provavelmente o último.

De qualquer forma, usar um endereço específico na variável MCAST_GRP resultará em um erro, portanto, usar uma string em branco obtém pelo menos o código para resolver o problema descrito pelo OP.

Este código pode ser reutilizado várias vezes no mesmo processo, embora ainda não tenha testado se vários processos podem usá-lo com êxito. Eu testei usando a estrutura asyncio do python, portanto, vários soquetes escutam no mesmo thread.

Além disso, para suporte multiplataforma, você também pode fazer com que esse código funcione em sistemas operacionais nix e, nesses sistemas, você pode definir MCAST_GRP para um endereço específico.

EDITAR:

Recentemente me depareieste recurso do MSque dá um exemplo que parece permitir o uso de um endereço de grupo multicast específico em vez de vincular a todos. Envolve definir mais algumas opções na variável multicast_grp_req. Além disso, o exemplo é o código C++, não python, mas eles são semelhantes o suficiente para entender a essência.

Espero que isto ajude :)

informação relacionada