Quali sono i modi migliori per serializzare e annullare la serializzazione dei messaggi di rete per il gioco multiplayer in C / C ++?


11

Stiamo utilizzando JSON in questo momento e vogliamo passare a un formato binario per alcuni tipi di messaggi tra client e server.

Devo solo leggere le strutture nel socket? Usa buffer / parsimonia proticol?

Come dovrei rappresentare matrici di dati?

Come dovrebbe essere l'interfaccia per l'imballaggio / il disimballaggio dei dati?

Risposte:


12

Assumendo ...

  1. stai parlando di convertire in un buffer di byte
  2. Stai utilizzando UDP e le prestazioni sono un problema

Cerca di evitare di sprecare spazio nel pacchetto per definire la struttura. IE invia, come minimo, un byte per indicare il tipo di pacchetto, quindi presuppone che ciascun pacchetto ricevuto segua la struttura predefinita per quel tipo di pacchetto

Devo solo leggere le strutture nel socket? Usa buffer / parsimonia proticol?

  • Sì, leggi l'intera struttura SE AVETE BISOGNO dell'intera struttura
  • No, crea tu stesso la struttura del pacchetto, questo sarà sicuramente più piccolo della serializzazione usando questi metodi; dovresti sapere esattamente quali dati devono includere il pacchetto

Come dovrei rappresentare matrici di dati?

  • Come matrici di dati. Durante la ricezione, continuare a leggere il buffer fino alla fine dei dati per evitare di inviare un conteggio degli elementi dell'array

Come dovrebbe essere l'interfaccia per l'imballaggio / il disimballaggio dei dati?

  • Potresti facilmente impostare un sacco di metodi per convertire i tipi di base in byte, da lì basarti su questi metodi per convertire anche tipi personalizzati. I dettagli su come fare questo potrebbero essere trovati quasi ovunque sono sicuro (io uso C # personalmente)

Un'ultima cosa, la dimensione del pacchetto è una preoccupazione, specialmente per un'istantanea: size = packetSize x entity x connectedPlayers; Quindi potresti avere 60 x 10 x 16 = 9.600 byte per pacchetto Quindi inviando questo 20 volte al secondo: = 192.000 bps = 187 KBps. Questa è ovviamente una banda alta con velocità di upload. Pertanto, ove possibile, è necessario ridurre al minimo ciascuno dei fattori che contribuiscono alla dimensione del pacchetto.

Questo articolo mi ha aiutato immensamente: Valve Multiplayer Networking


Un altro articolo che ho scoperto durante la lettura di varie domande sulla serializzazione degli oggetti e sulla rete qui alcune settimane fa è stato questo che descrive come il motore Unreal lo fa. Un buon punto di confronto per la sorgente Valve.
Martin Foot,

1
Il metodo dell'array non funzionerà nel caso generale: dov'è la "fine dei dati"? Anche se i tuoi messaggi sono delimitati, ciò significherebbe che non puoi avere più di 1 array per struttura. Per risolvere questo problema, il poster originale potrebbe attenersi a matrici di lunghezza fissa o garantire che vi sia solo 1 matrice per struttura (alla fine della struttura) o inviare un valore di conteggio all'inizio della matrice.
Kylotan,

Un altro consiglio: ricordati di trattare l'endianess, questo può essere molto evitante se non sai che esiste una cosa del genere.

Buon punto @Kylotan, concordo sul fatto che in alcuni casi questi dati extra non possono essere evitati; ma se mi ritrovo ad aggiungere più array a un singolo pacchetto, prenderei invece in considerazione l'invio di più pacchetti
Effettivamente005

1

Questo problema è stato risolto da Google e Facebook:

  1. Buffer di protocollo di Google - Google è un grande utente di C ++:

    I buffer di protocollo sono un modo per codificare i dati strutturati in un formato efficiente ma estensibile. Google utilizza i buffer di protocollo per quasi tutti i suoi protocolli RPC e formati di file interni.

  2. Apache Thrift (precedentemente Facebook):

    Thrift è un framework software per lo sviluppo di servizi multilingua scalabili. Combina uno stack software con un motore di generazione di codice per creare servizi che funzionano in modo efficiente e senza soluzione di continuità tra C ++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C #, Cocoa, JavaScript, Node.js, Smalltalk e OCaml.


I buffer del protocollo di Google sono troppo lenti per i giochi in tempo reale su larga scala. Li ho trovati piuttosto carini per la prototipazione e per i numeri di giocatori più piccoli a causa del controllo delle versioni, tuttavia. Come al solito, il tuo profiler racconta la vera storia.
Patrick Hughes,

Bene, sono abbastanza buoni per Google e Google si adatta abbastanza bene e hanno funzionato bene quando li ho usati. Ecco perché li ho raccomandati.
un secchione pagato

Google non richiede prestazioni in tempo reale. Google richiede affidabilità e tempo di attività, entrambi ben serviti dai buffer di protocollo. La complessità di tutto quel controllo delle versioni di fallback e della generazione del codice boilerplate aggiunge un sovraccarico e quando si inviano e si ricevono 1000 aggiornamenti a intervalli di 50-100 msec si sommano. Profilare un buffer di protocollo con diverse versioni precedenti rispetto a un serializzatore codificato specifico per i dati disponibili. @ indeed005 ne ha l'idea.
Patrick Hughes,

+1, perché sebbene questi formati siano un po 'troppo grandi e lenti per la maggior parte dei giochi in tempo reale o con larghezza di banda elevata (a causa del contenimento di informazioni aggiuntive che consentono di ricostruire pacchetti arbitrariamente complessi), ciò non significa che non siano utili in alcuni giochi, ad es. a turni. Se l'ottimizzazione di ogni risorsa non è necessaria, questi formati possono farti risparmiare molto tempo e sono sicuramente più efficienti di JSON.
Kylotan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.