JSON-Serialisierung für Netzwerk-Kommunikation

Algorithmen, Sprachunabhängige Diskussionen zu Konzepten, Programmiersprachen-Design
Antworten
Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

JSON-Serialisierung für Netzwerk-Kommunikation

Beitrag von Glocke » Mo Apr 08, 2013 12:38 am

Hi, vor einiger Zeit hatte ich ein kleines Networking-Framework auf Basis von SDL_net und C++ gebaut, um "Events" (effektiv Strukturen mit Primitivdaten, ohne Pointer oder STL-Container) via TCP zu senden und zu empfangen. Das ganze wollte ich durch Serialisierung etwas vereinfachen, indem ich keine Events mehr sende sondern direkt einen String (der meine serialisierten Daten enthält). Da ich aus meinen eigentlichen Daten eh die Events erstellen würde, kann ich genauso gut gleich einen String erzeugen... das ist wahrscheinlich einfacher zu handhaben.

Auf jeden Fall habe ich mir einige einfache Serialisierungen angesehen. INI-Dateien fallen raus, weil sie typlos speichern. XML ist mir zu viel drumrum, wenn ich die Daten via Netzwerk versenden möchte. Nun bin ich bei JSON stehengeblieben und habe mir eine kleine Library (420-Zeilen-Headerfile) gebastelt. Effektiv ist das eine kleine Datenstruktur die entsprechend der JSON-Syntax Daten serialisieren und deserialisieren kann.

Nun meine Frage: Ist JSON zur Serialisierung in meinem Fall geeignet? Ich möchte meine Daten mit möglichst wenig Overhead rumschicken - aber nicht ganz auf der Lowlevel-Schiene (d.h. byteweise, sondern eher zeichenweise - daher der Ansatz der Serialisierung). Ich weiß es gibt JSON-Bibliotheken wie Sand am Meer - aber irgendwie ging die Headerdatei recht schnell zu schreiben...

LG Glocke

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8859
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: JSON-Serialisierung für Netzwerk-Kommunikation

Beitrag von Xin » Mo Apr 08, 2013 11:11 am

Glocke hat geschrieben:Hi, vor einiger Zeit hatte ich ein kleines Networking-Framework auf Basis von SDL_net und C++ gebaut, um "Events" (effektiv Strukturen mit Primitivdaten, ohne Pointer oder STL-Container) via TCP zu senden und zu empfangen. Das ganze wollte ich durch Serialisierung etwas vereinfachen, indem ich keine Events mehr sende sondern direkt einen String (der meine serialisierten Daten enthält). Da ich aus meinen eigentlichen Daten eh die Events erstellen würde, kann ich genauso gut gleich einen String erzeugen... das ist wahrscheinlich einfacher zu handhaben.
Falls Deine Struktur keine Zeiger enthält, erscheint es mir am einfachsten, diese zu verschicken, denn dann ist sie ja bereits serialisiert.
Glocke hat geschrieben:Auf jeden Fall habe ich mir einige einfache Serialisierungen angesehen. INI-Dateien fallen raus, weil sie typlos speichern. XML ist mir zu viel drumrum, wenn ich die Daten via Netzwerk versenden möchte. Nun bin ich bei JSON stehengeblieben und habe mir eine kleine Library (420-Zeilen-Headerfile) gebastelt. Effektiv ist das eine kleine Datenstruktur die entsprechend der JSON-Syntax Daten serialisieren und deserialisieren kann.
JSON ist auch typlos!? Es spiegelt zwar eine Struktur wieder, aber es sagt eben nicht welche... ^^

Wenn Du Dich aber sowieso nur mit Dir selbst unterhältst, so spricht auch nichts dagegen, JSON über TCP zu nehmen oder kleine Datenhäppchen über UDP.
Glocke hat geschrieben:Nun meine Frage: Ist JSON zur Serialisierung in meinem Fall geeignet? Ich möchte meine Daten mit möglichst wenig Overhead rumschicken - aber nicht ganz auf der Lowlevel-Schiene (d.h. byteweise, sondern eher zeichenweise - daher der Ansatz der Serialisierung). Ich weiß es gibt JSON-Bibliotheken wie Sand am Meer - aber irgendwie ging die Headerdatei recht schnell zu schreiben...
JSON ist entsprechend für Deine Anforderungen quasi gemacht worden: Es wird gerne für Ajax verwendet, um Daten für Websites nachzuladen, also möglichst wenig Overhead, aber eben auch nicht ganz LowLevel.

Klingt erstmal nach einer sinnvollen Entscheidung, um serialisierte Daten zu senden. Nur wenn Du Dir die Serialisierung auf Dauer sowieso sparen kannst - weil es keine Zeiger gibt - dann würde ich bei Event-Strukturen bleiben.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: JSON-Serialisierung für Netzwerk-Kommunikation

Beitrag von Glocke » Mo Apr 08, 2013 12:01 pm

Xin hat geschrieben:JSON ist auch typlos!? Es spiegelt zwar eine Struktur wieder, aber es sagt eben nicht welche... ^^
Naja ein Typ ist quasi angedeutet: Strings beginnen und enden mit ", Zahlen und Bool'sche Variablen sind direkt erkennbar und Arrays und Objekte sind mit [ ] bzw. { } geklammert. Das ist für mich "typ"-iger als INI :P
Xin hat geschrieben:JSON ist entsprechend für Deine Anforderungen quasi gemacht worden: Es wird gerne für Ajax verwendet, um Daten für Websites nachzuladen, also möglichst wenig Overhead, aber eben auch nicht ganz LowLevel.
Ja, bei Ajax-Anwendungen bin ich bereits mit JSON in Kontakt gekommen. Daher kenne und mag ich es :)
Xin hat geschrieben:Klingt erstmal nach einer sinnvollen Entscheidung, um serialisierte Daten zu senden.
Danke, das wollte ich hören :D
Xin hat geschrieben:Nur wenn Du Dir die Serialisierung auf Dauer sowieso sparen kannst - weil es keine Zeiger gibt - dann würde ich bei Event-Strukturen bleiben.
Naja ich würde aus meinen eigentlichen Objekten und Zeigern die Events mit den Primitivdaten basteln. Ob ich da meine Daten in ein struct stecke oder in ein JSON-Objekt, macht da ja erstmal keinen großen Unterschied.
Beim Senden und Empfangen der Events habe ich irgendwie die "Angst", dass da ein paar Bytes verloren gehen können - vllt. durch außer acht gelassenen Datentyp-Architektur-Kombinationen oder sonstwas. Ich fühle mich irgendwie nicht so wohl dabei :D Das Senden eines Strings mit fester Länge (d.h. erst Sende ich die Länge als std::size_t und dann den String als char* mit eben dieser Länge) erscheint mir dabei transparenter, weil ich zum Debuggen sehr schnell Informationen ausgeben oder in eine Logfile umleiten kann, die dann sofort für mich lesbar sind.

EDIT: Und noch ein wichtiger Vorteil aus meiner Sicht: Das Framework ist so "runder" und "abgeschlossener". Bisher musste ich (als Framework-Verwender-Sicht) für meine Event-Strukturen eine Event* Event::assemble(void* buffer) Methode implementieren. Ich habe mich immer gefragt: "Warum machst du sowas? Wenn du ein Framework findest wo du solche Internals noch beim Verwenden machen musst, nimmst du doch selber ein anderes!". Mit der Serialisierung würde direkt nach dem Laden ein JSON Objekt deserialisiert werden - egal welche konkreten Daten es enthält. So kann ich wirklich "noch einfacher" meine JSON Objekte reinpushen und neue rauspoppen, ohne mir um irgendwelche Internals und ekelhaften Typecasts (die eh nur zu Fehlern führen xD) einen Kopf machen zu müssen :lol:

LG Glocke :)

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8859
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: JSON-Serialisierung für Netzwerk-Kommunikation

Beitrag von Xin » Mo Apr 08, 2013 12:42 pm

Glocke hat geschrieben: Naja ich würde aus meinen eigentlichen Objekten und Zeigern die Events mit den Primitivdaten basteln. Ob ich da meine Daten in ein struct stecke oder in ein JSON-Objekt, macht da ja erstmal keinen großen Unterschied.
Beim Senden und Empfangen der Events habe ich irgendwie die "Angst", dass da ein paar Bytes verloren gehen können - vllt. durch außer acht gelassenen Datentyp-Architektur-Kombinationen oder sonstwas. Ich fühle mich irgendwie nicht so wohl dabei :D Das Senden eines Strings mit fester Länge (d.h. erst Sende ich die Länge als std::size_t und dann den String als char* mit eben dieser Länge) erscheint mir dabei transparenter, weil ich zum Debuggen sehr schnell Informationen ausgeben oder in eine Logfile umleiten kann, die dann sofort für mich lesbar sind.
Das sehe ich dann wieder ein wenig anders.

Wenn Du size_t nutzt, solltest Du erstmal sizeof( size_t ) senden, ansonsten könnte es Dir passieren, dass ein 32-Bit und 64 Bit Kompilat nicht kompatibel sind. Ich würde zu "unsigned short" raten. Wenn Du mehr als 64kB schickst, würde ich den Sinn des Events überdenken...

Wenn Du Floats verschickst, dann beachte, dass eine Umrechnung stattfindet von Binär nach Dezimal. Du kannst zwar alle binären Zahlen Dezimal darstellen und entsprechend natürlich auch wieder in gültige Binärzahlen umrechnen, aber Du musst sicher gehen, dass Du nicht nach 5 Stellen hinter dem Komma die Zahl rundest. In dem Fall kommt nämlich eine andere Zahl beim Empfänger an. Hier würde ich eher das Bitmuster in einen String mit hexadezimalen Ziffern umwandeln, da Du das komplette und eindeutige Bitmuster einer Float so in genau 8 Ziffern unterbringen kannst.

Du hast mit JSON Overhead beim erzeugen des JSON-Textes und natürlich auch wieder beim Einlesen.

Wie gesagt - es gibt nicht nur Vorteile. Wenn Du eine Struktur hast, die keine Zeiger hat (und keine fragwürdigen Primitive wie size_t), würde ich diese Byte für Byte als char-Array übertragen. Ggfs noch mit einem Little/BigEndian-Marker oder per Definition das Format festlegen.
Glocke hat geschrieben:EDIT: Und noch ein wichtiger Vorteil aus meiner Sicht
Jeder Vorteil ist an anderer Stelle ein Nachteil. Du musst Dein System ausbalancieren, so dass es sich für Dich gut anfühlt - und natürlich, dass es läuft (ein nicht zu verachtender, aber gar nicht so selbstverständlicher Vorteil ^^).

Du baust Software immer für ein System. Das eine System ist von der CPU schnell, lädt aber langsam (Computer mit Disklaufwerk z.B. oder eben Netzwerk) oder aber es lädt schnell, aber die CPU ist langsam (Festplatte liefert genug Daten um eine Animation RAW abzuspielen, denn die CPU könnte nicht die Dekomprimierung in Echtzeit übernehmen).
Heute sind Computer rasend schnell. Ich habe einen i7 mit SSD Laufwerk. Und trotzdem kannst Du auch diesen Computer problemlos in Grenzbereiche bringen, wo Du eben Deinen Algorithmus ausbalancieren musst, um das Maximum an Effizienz zu erreichen. Das macht auch bei realen Anwendungen auf der Kiste schnell mal 50% Zeitersparnis aus, was alleine im Testfall schon mehrere Minuten ausmacht.

Dein Flaschenhals ist das Netzwerk. Du musst also Vorteile suchen, die das Netzwerk egalisieren, bzw. die Sache wenigstens nicht noch schlimmer machen. JSON wird also vermutlich nie ein Problem für Dein Framework sein, bis Netzwerke so reaktionsschnell werden, dass sie die CPU in Bedrängnis bringen könnten.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: JSON-Serialisierung für Netzwerk-Kommunikation

Beitrag von Glocke » Mo Apr 08, 2013 1:50 pm

Xin hat geschrieben:Wenn Du size_t nutzt, solltest Du erstmal sizeof( size_t ) senden, ansonsten könnte es Dir passieren, dass ein 32-Bit und 64 Bit Kompilat nicht kompatibel sind. Ich würde zu "unsigned short" raten. Wenn Du mehr als 64kB schickst, würde ich den Sinn des Events überdenken...
Vielleicht verwende ich noch besser einfach std::uint16_t oder sowas dafür.
Xin hat geschrieben:Wenn Du Floats verschickst, dann beachte, dass eine Umrechnung stattfindet von Binär nach Dezimal. Du kannst zwar alle binären Zahlen Dezimal darstellen und entsprechend natürlich auch wieder in gültige Binärzahlen umrechnen, aber Du musst sicher gehen, dass Du nicht nach 5 Stellen hinter dem Komma die Zahl rundest. In dem Fall kommt nämlich eine andere Zahl beim Empfänger an.
Okay das sollte ich mir nochmal genau ansehen. Bisher hatte ich die einfach mit std::stod() konvertiert. Aber dabei tritt genau das Problem auf, was du geschildert hast.
Xin hat geschrieben:Du hast mit JSON Overhead beim erzeugen des JSON-Textes und natürlich auch wieder beim Einlesen.
Ja, das nehme ich in kauf.
Xin hat geschrieben:Dein Flaschenhals ist das Netzwerk. Du musst also Vorteile suchen, die das Netzwerk egalisieren, bzw. die Sache wenigstens nicht noch schlimmer machen. JSON wird also vermutlich nie ein Problem für Dein Framework sein, bis Netzwerke so reaktionsschnell werden, dass sie die CPU in Bedrängnis bringen könnten.
Da bin ich beruhigt :mrgreen:

Antworten