¿Solución para el descubrimiento de pares LAN ligeros?

9

Construí una biblioteca para programación puramente multiplataforma. Mis juegos creados con él funcionan bien en Android, PC, Linux, Mac, etc.

La biblioteca ENET proporciona las capacidades de red, por lo tanto, toda la comunicación entre mis aplicaciones no es compatible con TCP o UDP, sino solo en el protocolo personalizado, incluso si está basado en UDP en última instancia.

No creo que sea posible hacer lo que quiero con ENET, ¡por eso pido ayuda aquí!

Digamos que tengo el mismo juego ejecutándose en mi teléfono Android, mi computadora portátil y mi PC. Todos están en la misma red wifi y, por lo tanto, en una LAN, ya sea punto de acceso Wifi (?) O el enrutador doméstico.

Necesito que cada uno de esos 3 pares descubra los otros dos en la red. Esto está destinado solo a encontrar la IP de las aplicaciones vivas en la red LAN, para poder albergar juegos multijugador entre ellas.

Solo puedo pensar en una forma efectiva de hacer esto, la transmisión UDP, esperar respuestas, pero si esa es la solución, necesito algo pequeño, ya que es el único propósito de la implementación.

Otra forma podría ser intentar conectarse a todas las IP en el subrango de direcciones LAN, pero no creo que el sistema operativo esté conmigo en este caso: p

Grimshaw
fuente
2
Creo que algunas transmisiones UDP son el camino a seguir, y no entiendo sus objeciones, ¿o es que ENET no admite transmisiones?
Roy T.
Exactamente, no lo hace, solo puede transmitir a compañeros ya conocidos ...
Grimshaw
stackoverflow.com/questions/683624/… ¿Influye esto en una respuesta?
Grimshaw

Respuestas:

5

Como mucha gente ha estado diciendo, la solución sería usar la transmisión UDP , pero hay muchos detalles de implementación involucrados. Recientemente me encontré con el mismo problema, y ​​después de encontrar una solución, publiqué un blog y un proyecto de muestra en forma de servidor / cliente de chat LAN. Voy a resumirlos aquí, pero debe consultarlos para obtener más detalles y un código real.

Así es como funciona, basado en una descripción de Lee Salzman, creador de ENet:

  • Su servidor de juegos se ejecuta en un socket, como un host ENet
  • El servidor también se une a un puerto conocido de "escucha", como un socket UDP normal (es decir, no un host ENet)
  • El cliente envía un mensaje de difusión UDP (es decir, IP 255.255.255.255) a ese puerto de escucha y espera respuestas
  • Todos los servidores en la LAN recibirán ese mensaje de "escaneo" y responderán. Idealmente, puede responder con el puerto en el que se ejecuta el servidor de juegos (ENet host); de esa manera no tiene que tener su servidor de juegos ejecutándose en un puerto fijo)
  • Después de que el cliente haya recibido algunas respuestas, sabrá qué servidores están presentes. Luego puede elegir uno de ellos para conectarse, como un par ENet normal. En este punto, el cliente ya no necesita el socket UDP "escáner".

La buena noticia es que ENet proporciona funciones de contenedor para usar sockets , por lo que puede hacer todo en ENet. La mala noticia es que el envoltorio es extremadamente delgado; necesitarás saber sobre programación de socket , como lo que select()hace. Es por eso que lo aliento a que lea la publicación del blog y el proyecto de muestra para que pueda copiar / pegar el código y ahorrar mucho tiempo.

Aquí hay algunas notas y dificultades si elige hacer su propia implementación:

  • El oyente / escáner debe ser UDP, por lo que debe crearlos utilizando enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM)(o SOCK_DGRAMpara la programación de sockets antiguos)
  • Para el servidor "oyente", permita que la dirección del puerto se reutilice usando enet_socket_set_option(socket, ENET_SOCKOPT_REUSEADDR, 1)(o SO_REUSEADDR) para que varios servidores puedan ejecutarse en la misma IP
  • Para el "escáner" del cliente, debe habilitar las transmisiones en el socket UDP utilizando enet_socket_set_option(scanner, ENET_SOCKOPT_BROADCAST, 1)(o SO_BROADCAST), de lo contrario no puede enviar a la dirección de transmisión. Esto es un característica de seguridad , para dificultar la inundación accidental de la red.

Lamentablemente, esta no es exactamente una solución "ligera"; el proyecto de muestra registra unos pocos cientos de LOC en total. Sería bueno si esto se empaquetara en una biblioteca de utilidades para ENet, pero descubrí que para los servidores de juegos, a menudo desea enviar más información específica del juego con la respuesta del servidor para que esto sea útil, como:

  • El tipo de juego (por ejemplo, "cooperativo", "deathmatch")
  • El "mapa", "nivel" o "campaña" que ejecuta el servidor
  • El número de jugadores y jugadores máximos para el servidor
  • Cualquier otra información específica del juego que afectará la decisión del cliente de conectarse o no. Piense en los "navegadores del servidor" en los juegos y en el tipo de información que muestran.
congusbongus
fuente
Esto es exactamente lo que estaba pensando. La transmisión es el camino a seguir.
Lolums
3

Cuando no desee abandonar su biblioteca, puede usar la fuerza bruta e intentar conectarse a cada una de las direcciones posibles. La mayoría de las líneas domésticas son redes de clase C (/ 24) donde los primeros 24 bits de la dirección IP son iguales y los últimos 8 bits difieren. Por lo tanto, solo tiene 255 direcciones IP posibles.

Pero aún así, hacer una transmisión UDP sería la alternativa más limpia. Simplemente envíe un paquete UDP a 255.255.255.255 y todos los clientes detrás del mismo enrutador lo recibirán. Luego pueden enviar una respuesta a la IP de origen y al puerto de origen del paquete para informar al remitente que están presentes.

Philipp
fuente
2
Por favor , por favor, por favor , por favor , no hagas fuerza bruta.
Trevor Powell
@TrevorPowell ... porque ...?
Philipp
2
Porque es la solución incorrecta. No funcionará en universidades (que no usan redes de clase c) o en empresas (que tampoco suelen usar redes de clase c), y al personal de TI tampoco les gustará mucho la carga causada por hacer que cada jugador haga La fuerza bruta intenta enviar mensajes a cada dirección IP de su red cada vez que hace clic en el botón "Actualizar". Es solo una mala solución al problema . Esta cuestión de localizar pares potenciales sin un servidor matemático es precisamente para qué sirve la transmisión. Usar difusión. Es mejor en todos los sentidos. :)
Trevor Powell
1

Puede echar un vistazo a DNS-SD / ZeroConf / Avahi / Bonjour / mDNS . Es lo que Apple usa para compartir impresoras, carpetas de iTunes, etc., pero se ha adoptado en otros lugares. Avahi es la versión de código abierto que usa Linux (no estoy seguro si es solo Linux), no estoy seguro de qué tan portátil es todo (aunque hay implementaciones para la mayoría de las plataformas).

Habiendo dicho todo eso, probablemente sea más fácil simplemente hacer la transmisión UDP.

David C. Bishop
fuente