ruby - propio - ¿Cómo debería diseñar mi(principalmente) servidor de juegos basado en texto?
crear juegos para android gratis (4)
Piensa en MUDs / MUCKs pero tal vez con avatares o ilustraciones regionales. Mi idioma de elección es Ruby .
Necesito manejar múltiples conexiones persistentes con datos que se transfieren de forma asíncrona entre el servidor y sus diversos clientes. Una única base de datos se debe mantener actualizada según la actividad que se produce en las sesiones del cliente. La actividad en cada sesión de cliente puede requerir que muchos otros clientes se actualicen inmediatamente (un usuario ingresa a una sala, un usuario envía a otro usuario un mensaje privado).
Este es un proyecto de meta y un proyecto de aprendizaje , por lo que mi intención es reinventar una rueda o dos para aprender más acerca de la programación de red simultánea. Sin embargo, soy nuevo en programación simultánea y en red; anteriormente, he trabajado casi exclusivamente en el mundo de solicitudes HTTP sincrónicas y no persistentes en aplicaciones web. Por lo tanto, quiero asegurarme de que estoy reinventando las ruedas correctas .
Gracias a la excelente respuesta de Per goss , he comenzado a observar los aspectos internos de ciertos servidores HTTP, ya que las aplicaciones web generalmente pueden evitar las preocupaciones debido a la profundidad con que los propios servidores eliminan el problema.
No quiero usar EventMachine o GServer porque aún no entiendo lo que hacen . Una vez que tengo una idea general de cómo funcionan, qué problemas resuelven y por qué son útiles, me sentiré cómodo con eso. Mi objetivo aquí no es "escribir un juego", sino "escribir un juego y aprender cómo funcionan algunas de las cosas de nivel inferior". Tampoco estoy claro sobre los límites de ciertos términos; por ejemplo, ¿las "aplicaciones independientes de E / S" son un superconjunto de "aplicaciones controladas por eventos"? ¿Viceversa?
Por supuesto que estoy interesado en la manera correcta para lograr mi objetivo, si es que existe, pero en general quiero entender por qué es la manera correcta y por qué otras formas son menos preferibles.
Cualquier libro, libro electrónico, recurso en línea, proyectos de muestra u otras cositas que pueda sugerir es lo que realmente estoy buscando.
La manera en que estoy haciendo las cosas ahora es usando IO#select
para bloquear en la lista de sockets conectados, con un tiempo de espera de 0.1 segundos. Transfiere toda la información leída a una cola de lectura segura para subprocesos, y cada vez que alcanza el tiempo de espera, extrae datos de una cola de escritura segura para subprocesos. No estoy seguro de si el tiempo de espera debería ser más corto. Hay un segundo hilo que sondea la cola de lectura del subproceso de manejo de sockets y procesa las "solicitudes". Esto es mejor que cómo lo había trabajado inicialmente, pero aún así podría no ser ideal.
Publiqué esta pregunta en Hacker News y me vincularon con algunos recursos con los que estoy trabajando; cualquier cosa similar sería genial:
Recomiendo leer un poco sobre el diseño del servidor web de unicornio. Eso debería darte una idea de la conversación hilo vs. proceso.
Aunque probablemente no te guste escucharlo, aún así recomiendo empezar a investigar los servidores HTTP primero. Aunque la programación para ellos le pareció aburrida, síncrona y no persistente, eso se debe únicamente a que los creadores de los servidores hicieron su trabajo para ocultar los detalles sangrientos de usted tan tremendamente bien. Si lo piensa, un servidor web no lo es. sincrónico (no es que millones de personas tengan que esperar para leer esta publicación hasta que haya terminado ... concurrencia :) ... y porque estas bestias hacen su trabajo tan bien (sí, sé que les gritamos mucho, pero al final del día, la mayoría de los servidores HTTP son piezas sobresalientes de software) este es el punto de partida definitivo a considerar si desea aprender acerca del multihilo eficiente. Los sistemas operativos y las implementaciones de lenguajes de programación o juegos son otra buena fuente, pero quizás un poco más lejos de lo que pretendes lograr.
Si realmente quieres ensuciarte los dedos, te sugiero orientarte en algo como WEBrick primero: se envía con Ruby y está completamente implementado en Ruby, por lo que aprenderás todo sobre los conceptos de subprocesamiento de Ruby allí. Pero tenga cuidado, nunca se acercará al rendimiento de una solución Rack que se encuentra en la parte superior de un servidor web implementado en C, como thin .
Entonces, si realmente quiere hablar en serio, debería implementar su propia implementación de servidor en C (++) y probablemente sea compatible con Rack, si tiene la intención de admitir HTTP. Toda una tarea que diría, especialmente si quieres que tu resultado final sea competitivo. El código C puede ser tremendamente rápido, pero también es fácil ser tremendamente lento, yace en la naturaleza de las cosas de bajo nivel. Y aún no hemos discutido la administración de la memoria y la seguridad. Pero si realmente es su deseo, consígalo, pero primero buscaría implementaciones de servidor conocidas para obtener inspiración. Vea cómo funcionan con los hilos (agrupación) y cómo implementan ''sesiones'' (usted quería persistencia). Todo lo que desee se puede hacer con HTTP, incluso mejor si se utiliza con una interfaz REST inteligente, las aplicaciones existentes que admiten todas las características que ha mencionado son una prueba viviente de ello. Entonces, ir en esa dirección no sería del todo incorrecto.
Si aún desea inventar su propio protocolo propietario, bájelo en TCP / IP como el mínimo común denominador aceptable. Ir más allá de eso terminaría en un proyecto en el que probablemente seguirían codificando tus nietos. Eso es realmente tan bajo como me atrevería a decir cuando se trata de programación en red.
Ya sea que lo esté utilizando como biblioteca o no, busque en EventMachine y su modelo conceptual. Pasar por alto el IO impulsado por eventos (''no bloqueo'') en su viaje sería negligente en el contexto de aprender sobre / reinventar las ruedas correctas . Un aperitivo para la programación basada en eventos que explica los beneficios de node.js como un servidor web .
En función de sus requisitos: comunicación asincrónica, múltiples "suscriptores" que reaccionan a "eventos" que se publican centralmente; bueno, eso realmente suena como un buen candidato para una arquitectura basada en eventos / basada en mensajes .
Algunos libros que pueden ser útiles en su viaje (solo Linux / C, pero los conceptos son universales):
- Programación con hilos POSIX
- Programación de red UNIX, vol. I y II
- Programación avanzada en el entorno UNIX
- TCP / IP Illustrated, vol. I - IV
(Esos eran los clásicos)
- La interfaz de programación de Linux : si solo tiene la intención de comprar un libro, que sea este, todavía no he terminado, pero es realmente sorprendente y cubre todos los temas que necesita saber para su aventura.
Proyectos que quizás desee verificar:
- Apache 2, thin, mongrel, nginx, lighttpd, ..., cualquier servidor web que haya
- EventMachine (lo siento :)
- node.js
- Redes eficientes en un juego ( fuentes de Quake 3 )
No sé mucho sobre Ruby, lo siento, pero creo que la arquitectura debe ser impulsada por sus requisitos (maternidad, tarta de manzana ... lo sé).
Si está creando algo que necesita escalar para un gran número de usuarios, su arquitectura debe reflejar eso, y usted termina tomando todo tipo de decisiones que no necesariamente tiene que tomar si está operando a una escala más modesta.
El tiempo de respuesta también juega un papel importante: no creo que sea tan importante con los juegos de estilo MUD, pero para servidores web o juegos FPS, es un gran problema.
Habiendo dicho eso, los únicos sistemas similares a los que describes que conozco con detalle usan un modelo de programación impulsado por eventos: los clientes activan eventos, el sistema actualiza su estado interno y notifica a los clientes afectados. El "estado interno" se almacena en realidad en una aplicación separada, comunicando de nuevo mediante sockets: esto permite escalar la aplicación agregando más servidores para manejar la interacción del cliente. No estoy seguro de que necesite ese nivel de complejidad.
En verdad, el enhebrado es un problema real, y crea un código difícil de probar, por lo que, aunque la respuesta de dash-tom-bang está un poco fuera del tema, la capacidad de prueba es una preocupación importante.
La forma correcta es utilizar desarrollo impulsado por prueba. Luego descubrirá lo que necesita reinventar en el momento exacto en que necesita inventarlo.
Comience con una prueba que "conecte" y afirme que se devuelve el mensaje "hola, usuario". Hazlo paso a paso desde allí.