Effizientes Datenpaket für ein Client-Server-Netzwerk

8

Sprache: C ++

Meine Frage lautet wie folgt: Ich möchte wissen, was der beste oder zumindest beste Weg ist, um Daten vom Client zum Server zu packen und zu senden und umgekehrt. Es wird einige Daten geben, die ein einzelnes Paket bilden. Ein Paket hat eine "ID", die definiert, wofür es ist, und dann die Daten in einer festgelegten Reihenfolge für die "Aktion", der das Paket entspricht.

Für weniger leistungsabhängige Systeme würde ich nur Zeichenfolgen senden, die durch ein Leerzeichen getrennt sind. Dies sind die Daten der "Aktion" und das erste "Wort" der Paketkennung und die Verkettung von Anweisungen, die prüfen, ob eine Übereinstimmung vorliegt .

Für ein kritischeres System war das, was ich bisher gelernt habe, ungefähr so:

Erstellen Sie eine Zeichenfolge mit Paket-ID und Daten und senden Sie diese. Zum Entpacken könnte ich dann die erste Ganzzahl in der Zeichenfolge extrahieren und ein Array von Paket-Handlern mit Indizes haben, die der Paket-ID entsprechen, die sie verarbeiten, und einfach so etwas wie packetHandlers [packetID] .Process (packetData) tun.

Was denkst du darüber, irgendwelche Vorschläge? sehr geschätzt!

Grimshaw
quelle

Antworten:

10

Stellen Sie zunächst sicher, dass Sie tatsächlich ein ausgefallenes, effizientes Protokoll benötigen, bevor Sie Ressourcen für die Entwicklung verschwenden. Vergessen Sie nicht, dass das Debuggen / Ändern Ihres Spiels aufgrund Ihres ausgefallenen Protokolls schwieriger und zeitaufwändiger wird. Ich würde nur die Netzwerkkommunikation weg abstrahieren, damit die eigentliche Implementierung bei Bedarf in Zukunft leicht gegen eine effizientere ausgetauscht werden kann. Verwenden Sie das einfachste Protokoll, bis Sie auf Leistungsprobleme stoßen. Ein weiterer Vorteil des späteren Entwurfs Ihres Protokolls besteht darin, dass das Protokoll für die tatsächlich transportierten Daten im Vergleich zu den von Ihnen vorhergesagten Daten optimiert werden kann.

Nachdem Sie bestätigt haben, dass Sie ein ausgefallenes Protokoll benötigen, sehen Sie sich Protokolle an, für deren Entwicklung andere viel Zeit aufgewendet haben. Einige Beispiele:

  • (Update) Der ursprüngliche Entwickler von Protocol Buffers (v2) hat ein neues Protokoll namens Cap'n Proto entwickelt. Er erklärt seine Entwurfsentscheidungen und vergleicht sie mit anderen ähnlichen Bibliotheken, die kürzlich veröffentlicht wurden: Cap'n Proto, FlatBuffers und SBE .
  • Der größte Engpass von Google ist die Netzwerkkommunikation zwischen Computern. Daher wurde bei der Entwicklung von Protokollpuffern wahrscheinlich die Effizienz berücksichtigt . Behandelt ordnungsgemäß die Vorwärts- / Rückwärtskompatibilität ( wenn Sie sich entscheiden, Ihre Datenstrukturen zu ändern). Wird von allen wichtigen Google-Produkten (Google Mail, Suche usw.) verwendet.
  • Apache Thrift ist ein ähnliches Protokoll, das von Facebook verwendet wird.
  • RakNet ist eine Open-Source-Netzwerkbibliothek, die speziell für die Spieleentwicklung entwickelt wurde.
  • ZoidCom ist eine weitere Netzwerkbibliothek, die auf die Entwicklung von Spielen ausgerichtet ist. Es ist nicht Open Source, aber Sie können es trotzdem studieren, um Design-Hinweise zu erhalten.

Die erste Regel der Programmoptimierung: Tun Sie es nicht.
Die zweite Regel der Programmoptimierung (nur für Experten!): Tun Sie es noch nicht.

[ Michael A. Jackson ]

Mit anderen Worten: Ihr primärer Optimierungsparameter sollte sein: Lebensdauer (Lebensjahre pro Programmimplementierung). [ So programmieren Sie unabhängige Spiele. Folie 21. Jonathan Blow. ]]

Leftium
quelle
1
netter lesender Mann! Vielen Dank für die vollständige Antwort, es hat sicher geholfen, und ich folge Ihrem Rat vollständig, abstrahiere dies einfach und mache es
vorerst
Ich bin mir ziemlich sicher, dass Googles Anwendungsfall für Protokollpuffer keine Effizienz im Standard-Sinne war, sondern um die Kompatibilität zwischen allen möglichen Plattformen und zukünftigen Datenversionen zu maximieren (was in einem anderen Licht Effizienz bedeutet). Ich werde hier drüben sein und Ihre anderen Notizen nachlesen, eine sehr schöne Sammlung, damit ich mich wieder mit dem Thema vertraut machen kann.
Patrick Hughes
RakNet ist kein Open Source.
Gerstmann
@Gerstmann: Raknet ist Open Source (wieder einmal): github.com/OculusVR/RakNet
Leftium
0

Warum zwei verschiedene Codierungsschemata verwenden? Verwenden Sie einfach die zweite für jedes System. Halte es einfach.
Erwägen Sie die Verwendung der Delta-Komprimierung. Dh einen vollen Wert senden und danach nur noch die Dinge, die sich geändert haben. Nach einigen Spieliterationen wird wieder ein voller Wert gesendet.
Eine andere Kodierung, die Sie in Betracht ziehen könnten, ist Base 128 Varint. Google Protobufs verwenden es. Werfen Sie einen Blick auf die Seite "Codierung" des Entwicklerhandbuchs: Protokollpuffer-Codierung Könnte einige Bytes sparen.

Lurca
quelle
Das erste System, von dem ich gesprochen habe, war nur ein Beispiel aus einem anderen Projekt :) Ich habe die Idee der Delta-Komprimierung auf jeden Fall genossen, danke Kumpel!
Grimshaw
0

Was könnte ein Beispiel für die Daten sein, die Sie senden? Ich sehe keinen Grund, etwas übermäßig Phantasievolles zu tun. Sobald die Daten vollständig in den Puffer des Empfängers geladen sind, überprüfen Sie die erste intanhand ihres Werts. Anschließend wissen Sie, wie Sie den Rest der Daten verarbeiten.

So ein Paket , das vier Datenteile aufweist id, val1, val2und val2könnte wie folgt aussehen:

// I'm using words (one byte) so my sample data is short
00000001 00101000 00010110 00010100 

Wenn Sie das erste Byte lesen (von dem Sie wissen, dass es immer vorhanden ist), entscheiden Sie, wie der nächste Datensatz verarbeitet werden soll. Wenn das erste Wort (ID) ist 00000001, wissen Sie, dass drei weitere Wörter folgen, und das ist das Ende des Pakets. Um das Beispiel fortzusetzen, könnte man id = hat 00000010und Ihre Spezifikation besagt, dass für id - Wert 2, Sie verarbeiten float, float, floatin dieser Reihenfolge, die eine Spielerposition im Welt - Raum angeben könnte.

Stellen Sie sich vor, Sie schreiben Ihr eigenes binäres Dateisystem. Sie haben einen Header-Wert, der den Rest der Daten beschreibt, wo sie sich befinden (welche Position) und als welche Art von Daten sie behandelt werden sollen.

Nate
quelle
Verstanden, die einzige Frage, die ich noch habe, ist: Ist das Packen all dieser Ints und Floats in einer Standardzeichenfolge ausreichend, oder sollte ich mich für leichtere Datentypen entscheiden?
Grimshaw
Beginnen Sie, wie von anderen gesagt, mit der Zeichenfolge und sehen Sie, was passiert. Möglicherweise haben Sie an anderer Stelle in Ihrem Code einen Flaschenhals.
Nate