¿Cuáles son las mejores formas de serializar y deserializar mensajes de red para el juego multijugador C / C ++?

11

Estamos usando JSON en este momento y queremos pasar a un formato binario para algunos tipos de mensajes entre el cliente y el servidor.

¿Debería leer estructuras en el zócalo? Usar proticol tampones / ahorro?

¿Cómo debo representar matrices de datos?

¿Cómo debería ser la interfaz para empacar / desempacar datos?

Estado de detención
fuente

Respuestas:

12

Asumiendo...

  1. estás hablando de convertir a un búfer de bytes
  2. Está utilizando UDP y el rendimiento es una preocupación.

Intente evitar el desperdicio de espacio en su paquete para definir la estructura. IE envía, como mínimo, un byte para denotar el tipo de paquete, luego asume que cada paquete recibido sigue la estructura predefinida para ese tipo de paquete

¿Debería leer estructuras en el zócalo? Usar proticol tampones / ahorro?

  • Sí, lea la estructura completa SI NECESITA la estructura completa
  • No, haga la estructura del paquete usted mismo. Esto seguramente será más pequeño que la serialización usando estos métodos; debe saber exactamente qué datos debe incluir el paquete

¿Cómo debo representar matrices de datos?

  • Como matrices de datos. Al recibir, continúe leyendo el búfer hasta el final de los datos para evitar enviar un Conteo de los elementos de la matriz.

¿Cómo debería ser la interfaz para empacar / desempacar datos?

  • Podrías configurar fácilmente un montón de métodos para convertir tipos básicos a bytes, a partir de ahí, construir sobre estos métodos para convertir tipos personalizados también. Los detalles sobre cómo hacer esto se pueden encontrar en casi cualquier lugar, estoy seguro (uso C # personalmente)

Una última cosa, el tamaño del paquete es una preocupación, especialmente para una instantánea: tamaño = paquete tamaño x entidades x conectado jugadores; Entonces, puede tener 60 x 10 x 16 = 9,600 bytes por paquete. Luego enviar esto 20 veces por segundo: = 192,000 bps = 187 KBps. Obviamente, esta es una alta velocidad de carga de ancho de banda. Por lo tanto, la necesidad de minimizar cada uno de los factores que contribuyen al tamaño del paquete siempre que sea posible.

Este artículo me ha ayudado enormemente: Valve Multiplayer Networking

de hecho 005
fuente
Otro artículo que descubrí al leer varias preguntas sobre la serialización de objetos y las redes aquí hace unas semanas fue este que describe cómo lo hace el motor Unreal. Un buen punto de comparación para la fuente Valve.
Martin Foot
1
Su método de matriz no funcionará en el caso general: ¿dónde está el 'fin de los datos'? Incluso si sus mensajes están delimitados, significaría que no puede tener más de 1 matriz por estructura. Para solucionar esto, el póster original podría adherirse a matrices de longitud fija, o asegurarse de que solo haya 1 matriz por estructura (al final de la estructura), o enviar un valor de recuento al comienzo de la matriz.
Kylotan
Solo un consejo más: recuerde tratar la endianess, esto puede ser muy molesto si no sabe que tal cosa existe.
Buen punto @Kylotan, acepta que en ciertos casos no se pueden evitar estos datos adicionales; pero si me encuentro agregando múltiples arreglos a un solo paquete, consideraría enviar múltiples paquetes en su lugar
hecho
1

Este problema ha sido resuelto por Google y Facebook:

  1. Buffers de protocolo de Google: Google es un gran usuario de C ++:

    Las memorias intermedias de protocolo son una forma de codificar datos estructurados en un formato eficiente pero extensible. Google utiliza Protocol Buffers para casi todos sus protocolos RPC internos y formatos de archivo.

  2. Apache Thrift (anteriormente por Facebook):

    Thrift es un marco de software para el desarrollo escalable de servicios en varios idiomas. Combina una pila de software con un motor de generación de código para crear servicios que funcionan de manera eficiente y sin problemas entre C ++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C #, Cocoa, JavaScript, Node.js, Smalltalk y OCaml.

un nerd pagado
fuente
Los búferes de protocolo de Google son demasiado lentos para juegos en tiempo real a mayor escala. Sin embargo, los encontré bastante agradables para la creación de prototipos y números de jugadores más pequeños debido a las versiones. Como de costumbre, su perfilador contará la historia real.
Patrick Hughes
Bueno, son lo suficientemente buenos para Google, y Google escala bastante bien, y funcionaron bien cuando los usé. Por eso los recomendé.
un nerd pagado el
Google no requiere rendimiento en tiempo real. Google requiere confiabilidad y tiempo de actividad, ambos bien servidos por Protocol Buffers. La complejidad de todas las versiones de respaldo y la generación de código repetitivo agrega una sobrecarga y cuando envía y recibe 1000 actualizaciones a intervalos de 50-100 ms se suma. Perfile un búfer de protocolo de varias versiones anteriores contra un serializador codificado específico para los datos disponibles. @ Indeed005 tiene la esencia de esto.
Patrick Hughes
+1, porque aunque estos formatos son demasiado grandes y lentos para la mayoría de los juegos en tiempo real o de gran ancho de banda (debido a que contienen información adicional que le permite reconstruir paquetes arbitrariamente complejos), eso no quiere decir que no sean útiles en algunos juegos, por ej. los por turnos. Si no es necesario optimizar todos los recursos, estos formatos pueden ahorrarle mucho tiempo, y ciertamente son más eficientes que JSON.
Kylotan