Solução para descoberta de pares de LAN leve?

9

Criei uma biblioteca para programação puramente multiplataforma. Meus jogos feitos com ele funcionam bem no Android, PC, Linux, Mac etc.

Os recursos de rede são fornecidos pela biblioteca ENET, portanto, toda a comunicação entre meus aplicativos não é compatível com TCP ou UDP, mas apenas no protocolo personalizado, ainda que seja baseada no UDP.

Eu não acho que é possível fazer o que eu quero com a ENET, é por isso que peço aqui ajuda!

Vamos dizer que eu tenho o mesmo jogo rodando no meu telefone Android, meu laptop e meu PC. Eles estão todos na mesma rede wifi e, portanto, em uma LAN, seja seu ponto de acesso Wifi (?) Ou o roteador doméstico.

Eu preciso que cada um desses três pares descubra os outros dois na rede. Isso serve apenas para encontrar o IP de aplicativos ativos na rede LAN, para poder hospedar jogos multiplayer entre eles.

Só consigo pensar em uma maneira eficaz de fazer isso, transmissão UDP, respostas de espera, mas se essa é a solução, preciso de algo pequeno, pois é o único objetivo da implementação.

Outra maneira poderia ser tentar se conectar a todos os IPs no subintervalo de endereço LAN, mas não acho que o sistema operacional estaria comigo neste caso: p

Grimshaw
fonte
2
Eu acho que algumas transmissões UDP são o caminho a percorrer, e eu não entendo suas objeções a isso, ou é que a ENET não suporta transmissões?
Roy T.
Exatamente, isso não acontecer, ele só pode transmitir a seus pares já conhecidos ..
Grimshaw
stackoverflow.com/questions/683624/… Isso influencia uma resposta?
Grimshaw

Respostas:

5

Como muitas pessoas dizem, a solução seria usar a transmissão UDP , mas há muitos detalhes de implementação envolvidos. Recentemente, encontrei o mesmo problema e, depois de elaborar uma solução, criei uma postagem no blog e um projeto de amostra na forma de um servidor / cliente de chat da LAN. Resumirei esses aqui, mas você deve consultá-los para obter mais detalhes e código real.

Veja como funciona, com base na descrição de Lee Salzman, criador do ENet:

  • Seu servidor de jogos roda em um soquete, como um host ENet
  • O servidor também se liga a uma porta "escuta" conhecida, como um soquete UDP comum (ou seja, não um host ENet)
  • O cliente envia uma mensagem de transmissão UDP (ou seja, IP 255.255.255.255) para essa porta de escuta e aguarda respostas.
  • Todos os servidores na LAN receberão a mensagem "digitalização" e responderão. Idealmente, você pode responder com a porta na qual o servidor do jogo (host ENet) está sendo executado; dessa forma, você não precisa ter seu servidor de jogos rodando em uma porta fixa)
  • Após o cliente receber algumas respostas, ele saberá quais servidores estão presentes. Em seguida, você pode escolher um deles para conectar-se, como um parceiro ENet comum. Neste ponto, o cliente não precisa mais do soquete "scanner" UDP.

A boa notícia é que o ENet fornece funções de invólucro para o uso de soquetes , para que você possa fazer tudo no ENet. A má notícia é que o invólucro é extremamente fino; você precisará saber sobre programação de soquetes , como o que select()faz. É por isso que incentivo você a dar uma olhada na postagem do blog e no projeto de amostra para poder copiar / colar o código e economizar muito tempo.

Aqui estão algumas notas e armadilhas, se você optar por fazer sua própria implementação:

  • O ouvinte / scanner deve ser UDP, portanto, é necessário criá-los usando enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM)(ou SOCK_DGRAMpara a programação simples de soquetes antigos)
  • Para o servidor "ouvinte", permita que o endereço da porta seja reutilizado usando enet_socket_set_option(socket, ENET_SOCKOPT_REUSEADDR, 1)(ou SO_REUSEADDR) para que vários servidores possam ser executados no mesmo IP
  • Para o "scanner" do cliente, você deve habilitar as transmissões no soquete UDP usando enet_socket_set_option(scanner, ENET_SOCKOPT_BROADCAST, 1)(ou SO_BROADCAST), caso contrário, não poderá enviar para o endereço de broadcast. Esse é apenas um recurso de segurança , para dificultar a inundação acidental da rede.

Infelizmente, essa não é exatamente uma solução "leve"; o projeto de amostra gera algumas centenas de LOC. Seria bom se isso fosse empacotado em uma biblioteca de utilitários para ENet, mas eu descobri que, para servidores de jogos, muitas vezes você deseja enviar mais informações específicas do jogo com a resposta do servidor para tornar isso útil, como:

  • O tipo de jogo (por exemplo, "co-op", "deathmatch")
  • O "mapa", "nível" ou "campanha" que o servidor está executando
  • O número de jogadores e o máximo de jogadores para o servidor
  • Qualquer outra informação específica do jogo que afetará a decisão do cliente de se conectar ou não. Pense nos "navegadores do servidor" nos jogos e no tipo de informação que eles mostram.
congusbongus
fonte
Era exatamente isso que eu estava pensando. A radiodifusão é o caminho a percorrer.
Lolums 01/03
3

Quando não quiser sair da sua biblioteca, você pode simplesmente usar força bruta e tentar se conectar a cada um dos endereços possíveis. A maioria das redes domésticas são redes de Classe C (/ 24), onde os primeiros 24 bits do endereço IP são iguais e os últimos 8 bits diferem. Então você tem apenas 255 endereços IP possíveis.

Mas, ainda assim, fazer uma transmissão UDP seria a alternativa mais limpa. Basta enviar um pacote UDP para 255.255.255.255 e todos os clientes atrás do mesmo roteador o receberão. Eles podem enviar uma resposta ao IP de origem e à porta de origem do pacote para informar ao remetente que eles estão presentes.

Philipp
fonte
2
Por favor , por favor, por favor, por favor , não faça força bruta.
Trevor Powell
@TrevorPowell ... porque ...?
Philipp
2
Porque é a solução errada. Ele não funcionará em universidades (que não usam redes classe C) ou em empresas (que normalmente também não usam redes classe C), e a equipe de TI de qualquer uma das duas empresas não gostará intensamente da carga causada por todos os jogadores. a força bruta tenta enviar mensagens para todos os endereços IP da rede sempre que clicam no botão 'atualizar'. É apenas uma solução ruim para o problema . Essa questão de localizar possíveis pares sem um servidor de matemática é exatamente para que serve a transmissão. Use transmissão. É melhor em todos os sentidos. :)
Trevor Powell
1

Você pode dar uma olhada no DNS-SD / ZeroConf / Avahi / Bonjour / mDNS . É o material que a Apple usa para compartilhar impressoras, pastas do iTunes e assim por diante, mas foi adotado em outros lugares. Avahi é a versão de código-fonte aberto que o Linux usa (não tenho certeza se é apenas Linux), não tenho certeza de quão portátil é a coisa toda (embora existam implementações para a maioria das plataformas).

Dito tudo isso, provavelmente é mais fácil fazer a transmissão UDP.

David C. Bishop
fonte