Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Teorias sobre programacion cliente servidor

Iniciado por Altair, 06 de Marzo de 2013, 01:21:30 AM

« anterior - próximo »

Altair

Buenas,

estoy avanzando con mi proyecto y he llegado a un punto que creo que deberia meterle la opcion multiplayer, he pensado tanto red local como por Internet. Estoy pensando en usar MySQL tanto para la comunicacion como almacenar datos de lo que sea (perfiles de jugadores, rankings, etc)

Entiendo que depende bastante del tipo de juego, no es lo mismo un matamarcianos que un plataformas que un juego tipo Quake pero creo que poderse, se podria hacer con C/C++ y MySQL. El como se gestionen los datos y demas cosas internas es otro tema.

¿Estoy mas o menos en lo cierto?.

Gracias.

[EX3]

Cita de: Altair en 06 de Marzo de 2013, 01:21:30 AM
estoy avanzando con mi proyecto y he llegado a un punto que creo que deberia meterle la opcion multiplayer, he pensado tanto red local como por Internet. Estoy pensando en usar MySQL tanto para la comunicacion como almacenar datos de lo que sea (perfiles de jugadores, rankings, etc)
Aquí me he perdido. ¿Dices de usar una base de datos como canal de comunicación entre clientes y servidor? ??? Que me digas de usar la base de datos para almacenar de forma permanente los datos de perfiles de usuario, inventario, progresos, etc... tiene sentido, ¿pero para comunicación en tiempo real entre jugadores y servidor?

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Altair

Si, como canal de comunicacion. No se si es una buena forma pero parece funcionar, tengo que probarlo. Por ejemplo, supongamos una partida de matamarcianos de 3 jugadores.

Cada cliente toma "decisiones locales", como por ejemplo que una nave no puede disparar si no tiene municion y la envia al servidor. Es decir, al servidor solo se envian datos que se sabe que son correctos. ¿Como se enteran los otros 2 jugadores?.

El servidor MySQL tiene, basicamente, tres tipos de tablas. La de entrada de datos, en la que solamente pueden escribir (no confundir con actualizar); la de salida de datos, en la que solamente pueden leer. Los clientes escriben los datos en la de entrada casi continuamente, pues toda actualizacion de los datos de un cliente tiene que ser comunicada al servidor y, segun lo que sea, a los otros clientes. Los datos de la entrada se procesan y se escribe la respuesta en la tabla de salida. Los clientes leen la tabla de salida continuamente, puesto que no saben cuando va a haber un mensaje para ellos.

Estas dos tablas se estan actualizando continuamente, asi que cada X tiempo se tienen que borrar registros que ya no son utiles. Por ejemplo, si la partida ya dura 5 minutos, los registros de los 4 primeros minutos no son necesarios y deben ser borrados, lo cual aumenta la velocidad de las consultas en esas tablas. A tener en cuenta que se borran siempre registros que pertenecen al pasado.

Los mensajes tienen una estructura de este tipo: ORIGEN - DESTINO - MENSAJE - MARCA

ORIGEN es el nombre del jugador, fecha y hora. DESTINO el jugador al que enviamos. MENSAJE el texto al cliente. MARCA es el estado del mensaje, se usa para eliminar registros procesados.

Para evitar problemas de consistencia con los datos, como por ejemplo dos ordenes actualizando al mismo tiempo una variable con datos diferentes, las ordenes de la entrada se procesan una a una.

Basicamente es eso, creo que puede funcionar.

julen26

Cita de: Altair en 06 de Marzo de 2013, 08:04:49 AM
Cada cliente toma "decisiones locales", como por ejemplo que una nave no puede disparar si no tiene municion y la envia al servidor. Es decir, al servidor solo se envian datos que se sabe que son correctos. ¿Como se enteran los otros 2 jugadores?.
El servidor es el que también debe tomar esas decisiones por simplemente, seguridad. Si es solo una prueba, adelante. Generalmente se envían inputs para reducir el tráfico.

Cita de: Altair en 06 de Marzo de 2013, 08:04:49 AM
El servidor MySQL tiene, basicamente, tres tipos de tablas. La de entrada de datos, en la que solamente pueden escribir (no confundir con actualizar); la de salida de datos, en la que solamente pueden leer. Los clientes escriben los datos en la de entrada casi continuamente, pues toda actualizacion de los datos de un cliente tiene que ser comunicada al servidor y, segun lo que sea, a los otros clientes. Los datos de la entrada se procesan y se escribe la respuesta en la tabla de salida. Los clientes leen la tabla de salida continuamente, puesto que no saben cuando va a haber un mensaje para ellos.
He subrayado en negrita las dos cuestiones que "matarían" la jugabilidad debido a la latencia que podrían generar. Lo de enviar continuamente información... es un mal diseño del protocolo de comunicación (no siempre). Todo esto sin contar con que el protocolo sera TCP internamente dejando de lado varias ventajas que también aporta UDP, aunque esto sea menos importante si se aplican correctamente técnicas de predicción etc.

En general, para tiempo real creo que es una burrada, pero para otro sistema de datos que no requiera rapidez sería una buena idea (mmorpg etc.)

Altair

Si, lo de leer continuamente la tabla de salida es algo que tambien pienso que puede hacer caer el rendimiento. Creo que no es lo mismo desde el punto de vista de programacion una partida en red local que otra por internet, dado que el entorno es diferente.

He pensado en formas de optimizar eso, y se he han ocurrido dos cosas:

Primera, las lecturas de la tabla de salida se hacen solamente una vez cada segundo, eso deberia ser una ayuda para sobrecargar menos la comunicacion y el sistema, creo.

Segunda, cada cliente tiene su propia tabla de salida. Esto hace que el servidor escriba mas registros, uno por cada tabla de cliente, pero a cambio la lectura de la tabla de salida por parte de cada cliente creo que es mas eficaz al buscarse solamente los registos del segundo correspondiente y no tener que incluir el nombre del cliente.

Al combinar ambas cosas creo que podria ser un avance.

Por otra parte estoy buscando por Google el codigo fuente de algun juego multiplayer 2D para tener una idea mas clara de por donde tirar, pero de momento todo lo que estoy viendo por sourceforge son o masivos o 3D

julen26

#5
Yo hace unos meses que terminé un juego (Rounded Soccer, post de stratos) al que le metí un modo online bastante básico con un raking y un creador automático de partidas. Si lo pruebas podrás ver como va.

Si necesitas ayuda en hacer algo parecido no dudes en preguntarme. Dejé sin implementar la predicción en el cliente por no tener a nadie con quién realizar pruebas a distancia y por falta de ganas también, pero tenía la idea desarrollada.

Por cierto, para el ranking y el matchmaking sí que usé MySQL con un servidor PHP de intermediario, y créeme que se nota muchísimo la latencia de las consultas a la base de datos. Para la partida a tiempo real, decidí usar solo TCP, a pesar de haber pensado en hacerlo con UDP para obtener más rapidez. Pero es necesario crear un protocolo mínimo para el control de flujo, predicciones etc.

Fanakito

Yo te recomendaría, que si es tu primer juego multijugador evaluases utilizar alguna liberia de red consolidada, para ahorrar tener que pelearte con los detalles de "bajo nivel" de la red. Echale un vistazo a:

http://www.codeofhonor.com/blog/choosing-a-game-network-lib

Tambien te recomendaría que te patearas libros sobre juegos multiplayer o, al menos, los articulos que hay por ahi sobre la arquitectura multiplayer del Quake 3 o del Source, porque diseñar un multiplayer requiere mucho mucho curro.

Altair

Estoy mirando las diferentes opciones. Una cosa, mi proyecto lo estoy haciendo desde Linux, no me valen cosas de Windows a menos que pueda ver el codigo fuente y usarlo. Estoy usando la licencia LGPL.

Fanakito

Cita de: Altair en 06 de Marzo de 2013, 06:58:10 PM
Estoy mirando las diferentes opciones. Una cosa, mi proyecto lo estoy haciendo desde Linux, no me valen cosas de Windows a menos que pueda ver el codigo fuente y usarlo. Estoy usando la licencia LGPL.

Yo la que conozco es RakNet y esa te bajas el codigo fuente y te la compilas. Esta forma de distribución es la que tiene más sentido, especialmente en cosas como librerias de red, que la version Linux es casi obligatoria, porque si te quieres montar un servidor, aunque tu juego vaya a funcionar en Windows, montar los servidores en Linux no es raro (porque es más barato el hosting).

Altair

He estado mirando RakNet pero no me gusta por el tema de la licencia que usa.

Me he encontrado con esto http://content.gpwiki.org/index.php/Libraries#Networking

He miradoSDL_net, porque ya que uso las librerias SDL a saco, me parece una buena opcion. He conseguido poner en marcha un servidor y cliente TCP siguiendo el ejemplo de

http://content.gpwiki.org/index.php/SDL:Tutorial:Using_SDL_net

He trasteado un poco con el codigo del servidor y he conseguido que acepte dos clientes simultaneamente, cada uno funciona por su cuenta, parece una forma de comunicacion mas eficaz ya que creo que no se esta enviando y recibiendo continuamente datos, sino solo cuando se hace una peticion para enviar o recibir.

Altair

He hecho algunos "avances". He estado trasteando y he conseguido manejar 2 clientes simultáneamente, me he topado con lo que parece ser ciertas limitaciones, ya decia el aviso en la web que SDL_net es una libreria "basica". En este caso estoy probando con un servidor que acepta 10 clientes, del 0 al  9.

Hay que leer todos los clientes al mismo tiempo, de lo contrario la información enviada por el cliente se pierde.

Dado que para mi proyecto se tienen que cumplir ciertas condiciones (licencia compatible con LGPL, multiplataforma con al menos windows y linux, válido para juegos gratuitos y comerciales, librería activa) no parece fácil encontrar opciones. Ni en la lista que puse, ni en sourceforge ni en Google. Lo mas "aceptable" que he visto es esto http://think-async.com/Asio

Las demás opciones tienen alguno de los siguientes inconvenientes:
- Solo windows o linux
- Proyecto aparentemente inactivo
-Licencia de pago si el uso es comercial
- Licencia no compatible con LGPL
- Lenguaje diferente a C/C++

Leyendo sobre como funcionaba mas o menos cada algunas librerias creo que he encontrado algo que puede servir:

- Tabla de entrada, el cliente escribe en ella conforme envia datos, se vacía cada X tiempo.
- Tabla de salida, el cliente lee en ella continuamente SOLO si esta esperando respuesta del servidor, se vacía cada X tiempo.

De esta forma, si el cliente no esta enviando nada a entrada, tampoco lee nada en salida. Si el cliente envia datos, se espera X tiempo (¿1 segundo, por ejemplo?) y empieza a leer la tabla de salida. Teoricamente, esto podria ser mejor.

Altair

No sé si es lo más óptimo, pero empiezo a pensar que tanto el cliente como el servidor tengan instalado un servidor MySQL y un cliente MySQL, de esta forma pueden enviar y recibir datos del uno al otro.

Fanakito

Creo que vale la pena que sigas por la via SDL_net, porque usar un servidor de BBDD para un juego sencillo, aunque posible, creo que te va a dar más problemas que soluciones.

¿Que es lo que hace tu servidor y que problema hay en leer "todos los datos" de los jugadores? Precisamente, el loop del servidor suele ser leer los jugadores y devolver a cada jugador el nuevo estado de la partida. Cada cliente, por el otro lado, tiene que ocuparse de sincronizar el estado que muestra.

Creo que el problema que tienes se debe a que, posiblemente, te has enfocado en lo del MySQL y quieres que "dar posicion" y "recibir posicion enemigo" sean metodos que tu llames, cuando el "recibir la posicion enemiga", lo que en realidad debe ser es un "callback".

Luego tendrías que decidir donde se va a decidir la posición de la pelota, que en un juego multiplayer lo normal es que "el servidor mande".

Altair

Sí, más o menos pienso lo mismo.

SDL_net esta bien para juegos que requieran pocos participantes. Creo que el tema esta en que la lectura del cliente se hace en el bucle principal, como también tu dices, PERO se procesa en otro sitio, lo cual hace que los datos leídos se procesan una sola vez, y no una vez por cada cliente, al contrario de lo que se medio-sugiere en el ejemplo de SDL_net con TCP.

Creo que usar MySQL puede ser una opcion cuando tenemos un numero  grande y no determinado de clientes. ¿Como cuantos?,  tal vez cuando el sistema de lectura de clientes usando SDL_net "falle" porque no puede leerlos todos. Tambien cuando se sepa que van a ser muchos y no sea posible determinar cuantos, en plan multiplayer "masivo". Lo pongo entre comillas porque me refiero a casos en los que se lean clientes del orden de cientos (200, 500, etc).

En este segundo caso parece tener sentido usar en el cliente un servidor MySQL minimo, que se activa solamente cuando se juega. Posiblemente para crear ese "MySQL minimo" haya que compilar el código fuente de MySQL desde windows.

Una vea "aclarado"(teóricamente) esto, queda el tema de como conectar del servidor al cliente para enviar datos de respuesta. Se use SDL_net o MySQL vamos a necesitar una IP y un puerto. Y parece que SDL_net no lo da porque no ha sido pensada para eso:

IPadress, de la doc de SDL_net:

typedef struct {
    Uint32 host;            /* 32-bit IPv4 host address */
    Uint16 port;            /* 16-bit protocol port */
} IPaddress;

host
    the IPv4 address of a host, encoded in Network Byte Order.
port
    the IPv4 port number of a socket, encoded in Network Byte Order.

This type contains the information used to form network connections and sockets.

A tener en cuenta que lo que se busca es la IP pública.

Altair

Buenas, por fin puedo comunicar algunos avances que hice:

DATOS DE CLIENTE A SERVIDOR:
- Ordenador cliente:
-- Cliente MySQL

- Ordenador servidor
-- Servidor MySQL

DATOS DE SERVIDOR A CLIENTE:
- Ordenador cliente:
-- Servidor SDL_net

- Ordenador servidor
-- Cliente SDL_net

De esta forma, se envian y se reciben datos solamente cuando hace falta. La "pega" es que cuando se envian datos del servidor al cliente, el ordenador servidor tiene que tener, por cada cliente conectado, un programa que lea continuamente la base de datos para saber si hay que enviar informacion, y en caso afirmativo mandarla. La IP del cliente se puede obtener desde el servidor MySQL del ordenador servidor.

Parece un metodo aceptable cuando se tiene un numero alto y no determinado de clientes simultaneos.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.