[C++] Cross-platform (network) serialization

Pagina: 1
Acties:

  • dawuss
  • Registratie: Maart 2001
  • Laatst online: 01-02 20:46

dawuss

gadgeteer

Topicstarter
Voor mijn eerste kennismaking met networking onder C++ ben ik bezig van het maken van een (extreem simpele) Packet klasse, die zichzelf kan serializen en unserializen voor verzending over een netwerk stream.
Je zou verwachten dat hier pagina's vol over geschreven zijn op GoT en de rest van het internet, maar ik kan toch nergens echt een concreet antwoord vinden op mijn vragen :)
Afgezien van [rml][ C++/Linux] Networking, hoe structs verzenden?[/rml] heb ik hier op GoT niet echt concrete topics over network serialization gevonden :)

Ik zal eens beginnen met een relevant stukje uit het prototype van m'n Packet klasse:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Packet {
    private:
        int id;             
        int source;         
        int destination;
        string data;

    public:
        Packet(int id, int source, int destination, string s);
        Packet(char* cbuf);
        // <snip>
        void netPack(char*);
        void netUnpack(char*);


Nu is de netPack methode, die verantwoordelijk is voor het serializen van de data members, op het moment heel erg simpel:

C++:
1
2
3
4
5
6
7
void Packet::netPack(char* cbuf) {
    int size = this->getSize();
    char buf[size+1]; // reserve extra space for null
    char *bidx = buf; // index pointer

    char *lid = reinterpret_cast <char*> (&id);
    memcpy(bidx, lid, sizeof(this->id));


En het probleem zal duidelijk zijn: Hoe weet ik dat sizeof(int) aan de andere kant, waar dus ge-unserialized zal worden, gelijk is aan sizeof(int) op het lokale systeem?

Ik weet niet of er een naam is voor dit probleem, maar pointers richting de juiste documentatie zijn op dit moment erg welkom, want heb zelf geen flauw idee waar ik moet beginnen. Natuurlijk zijn hints over brakke constructies in mijn code ook van harte welkom ;)

Tot slot vraag ik me af of ik op dit niveau al rekening moet houden met byte-ordering. Moet ik de byte-representaties van de integers bijvoorbeeld eerst omzetten naar netwok byte order voor ik ze aanelkaar plak?

micheljansen.org
Fulltime Verslaafde Commandline Fetisjist ©


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 18:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

Waar is die char * cbuf voor die je meekrijgt? Ik zie verder niet dat je 'm gebruikt... En waarom serializeer je niet gewoon naar een stream? Toch veel handiger als je direct je primitieven dmv functies op die stream kunt zetten? Kun je gelijk rekening houden met het feit dat sommige types niet overeen komen tussen platforms (endianness, aantal bits). Wat je dan moet doen is gewoon zelf een afspraak maken over hoe types in elkaar moeten zitten, en bij serialization en deserialization zet je het formaat om naar het formaat wat het systeem gebruikt.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-05 14:03

curry684

left part of the evil twins

dawuss schreef op vrijdag 03 juni 2005 @ 12:17:
En het probleem zal duidelijk zijn: Hoe weet ik dat sizeof(int) aan de andere kant, waar dus ge-unserialized zal worden, gelijk is aan sizeof(int) op het lokale systeem?
Niet: daarom definieer je je protocol ook zonder 'ints' erin maar met 32-bits waardes, waardoor de implementatie aan de andere kant daar zelf zorg voor draagt :)
Tot slot vraag ik me af of ik op dit niveau al rekening moet houden met byte-ordering. Moet ik de byte-representaties van de integers bijvoorbeeld eerst omzetten naar netwok byte order voor ik ze aanelkaar plak?
Voor byteordering geldt hetzelfde: je legt in je protocol vast welke byteordering gebruikt wordt, en de implementatie aan beide kanten zoekt voor zichzelf maar uit of ze dan wel of niet byte-ordering moeten flippen ;)

Professionele website nodig?


  • dawuss
  • Registratie: Maart 2001
  • Laatst online: 01-02 20:46

dawuss

gadgeteer

Topicstarter
.oisyn schreef op vrijdag 03 juni 2005 @ 12:26:
Waar is die char * cbuf voor die je meekrijgt? Ik zie verder niet dat je 'm gebruikt... En waarom serializeer je niet gewoon naar een stream? Toch veel handiger als je direct je primitieven dmv functies op die stream kunt zetten? Kun je gelijk rekening houden met het feit dat sommige types niet overeen komen tussen platforms (endianness, aantal bits). Wat je dan moet doen is gewoon zelf een afspraak maken over hoe types in elkaar moeten zitten, en bij serialization en deserialization zet je het formaat om naar het formaat wat het systeem gebruikt.
Goed punt. Ik had nu in gedachten die verantwoordelijkheid bij de klasse te leggen die de Packets ook daadwerkelijk op de stream zet.
curry684 schreef op vrijdag 03 juni 2005 @ 12:41:
[...]

Niet: daarom definieer je je protocol ook zonder 'ints' erin maar met 32-bits waardes, waardoor de implementatie aan de andere kant daar zelf zorg voor draagt :)
Kun je dat misschien toelichten met een voorbeeld of iets dergelijks? Ik vat wel ongeveer waar je heen wil, maar ik zie 't niet echt voor me :)

micheljansen.org
Fulltime Verslaafde Commandline Fetisjist ©


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Simepl: je C++ definieert niet het protocol, maar het protocol definieert je C++. Dus als je protocol zegt dat je 32 bits waarden verzend, dan moet je in C++ een long gebruiken en checken dat je geen waarden >2G probeert erin te duwen.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

off-topic: ik durf bijna niet posten in dit admin/mod onderonsje :P
on-topic:

ik zie ook dat je een netUnpack functie hebt. Is die niet overbodig, als je ook een constructor hebt die ervoor zorgt dat je buffer omgetoverd wordt in een pakketje.

je implementatie van hoe je alles kopieert in die cbuf staat er niet bij, maar ik hoop dat je rekening houdt met variabele lengtes ;)

ASSUME makes an ASS out of U and ME


  • dawuss
  • Registratie: Maart 2001
  • Laatst online: 01-02 20:46

dawuss

gadgeteer

Topicstarter
MSalters schreef op vrijdag 03 juni 2005 @ 12:53:
Simepl: je C++ definieert niet het protocol, maar het protocol definieert je C++. Dus als je protocol zegt dat je 32 bits waarden verzend, dan moet je in C++ een long gebruiken en checken dat je geen waarden >2G probeert erin te duwen.
En er zijn geen vreemde exotische systemen die een "gekke" long hebben die niet 32 bits is?
Niet dat wat ik aan het schrijven ben daar ooit op gebruikt zal worden, maar 't gaat om het educatieve doel he ;)
HIGHGuY schreef op vrijdag 03 juni 2005 @ 12:53:
ik zie ook dat je een netUnpack functie hebt. Is die niet overbodig, als je ook een constructor hebt die ervoor zorgt dat je buffer omgetoverd wordt in een pakketje.
Eehm, ja, dat rammelt inderdaad nog een beetje ;) Ik moet bekennen dat ik niet precies weet welke kant ik er mee op wil, zeker niet nu ik ook nog eens ga kijken naar het direct verzenden over de stream, ipv opslaan in een character buffer.
je implementatie van hoe je alles kopieert in die cbuf staat er niet bij, maar ik hoop dat je rekening houdt met variabele lengtes ;)
Dat is wel de bedoeling ja ;)

micheljansen.org
Fulltime Verslaafde Commandline Fetisjist ©


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 18:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

dawuss schreef op vrijdag 03 juni 2005 @ 13:01:
[...]

En er zijn geen vreemde exotische systemen die een "gekke" long hebben die niet 32 bits is?
long is minstens 32 bits, als je een 32 bits waarde moet gebruiken heb je aan een long gegarandeerd voldoende, dat was MSalters punt. Je zit alleen nog wel met endianness, maar daar zijn API functies voor (htonl() en ntohl())

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-05 14:03

curry684

left part of the evil twins

dawuss schreef op vrijdag 03 juni 2005 @ 13:01:
[...]

En er zijn geen vreemde exotische systemen die een "gekke" long hebben die niet 32 bits is?
Niet dat wat ik aan het schrijven ben daar ooit op gebruikt zal worden, maar 't gaat om het educatieve doel he ;)
Het punt is dat dat je niet boeit. Jouw protocol schrijft voor hoe je de data verpakt, en de manier waarop je dat nu doet is met 32-bit little-endian signed integers en een zero-terminated octet-stream als string. Als dat jouw protocol is is dat jouw protocol, en heeft degene die aan de andere kant je protocol implementeert zich daar maar aan te schikken.

Het hele idee van een protocol is juist dat het ondubbelzinning vastligt, en dat de specifieke implementatie maar kijkt hoe ie dat afhandelt :)

Professionele website nodig?


  • El Psycho
  • Registratie: September 2002
  • Laatst online: 13-12-2025
dawuss schreef op vrijdag 03 juni 2005 @ 13:01:
En er zijn geen vreemde exotische systemen die een "gekke" long hebben die niet 32 bits is?
Niet dat wat ik aan het schrijven ben daar ooit op gebruikt zal worden, maar 't gaat om het educatieve doel he ;)
Als je je code ook op een ander platform (die misschien andere groottes voor de verschillende int's hanteert) zou willen gebruiken kan je ook je eigen type definiëren in een header file dat je in je gehele code include:

C++:
1
typedef long bits32;


en op implementaties op een andere platform:

C++:
1
typedef IntegertypeOpExotischPlatformDat4BytesGrootIs bits32;


Dan weet je zeker dat in ieder geval je eigen type 4 bytes groot is op elk platform.

[ Voor 5% gewijzigd door El Psycho op 03-06-2005 13:23 ]


  • dawuss
  • Registratie: Maart 2001
  • Laatst online: 01-02 20:46

dawuss

gadgeteer

Topicstarter
curry684 schreef op vrijdag 03 juni 2005 @ 13:17:
[...]

Het punt is dat dat je niet boeit. Jouw protocol schrijft voor hoe je de data verpakt, en de manier waarop je dat nu doet is met 32-bit little-endian signed integers en een zero-terminated octet-stream als string. Als dat jouw protocol is is dat jouw protocol, en heeft degene die aan de andere kant je protocol implementeert zich daar maar aan te schikken.

Het hele idee van een protocol is juist dat het ondubbelzinning vastligt, en dat de specifieke implementatie maar kijkt hoe ie dat afhandelt :)
In dit geval ben ik zelf ook verantwoordelijk voor het unpacken van de geserializede Packet's, dus ik heb volledige vrijheid in het protocol dat ik hanteer :)

In ieder geval is me nu wel het een en ander duidelijk geworden, dus ik duik weer eens fanatiek mijn code in, bedankt :)

micheljansen.org
Fulltime Verslaafde Commandline Fetisjist ©


  • Robbemans
  • Registratie: November 2003
  • Laatst online: 17-07-2025
Misschien een domme opmerking, maar kun je er geen XML van maken? Hoervoor is zeker een C++ library te vinden...

  • El Psycho
  • Registratie: September 2002
  • Laatst online: 13-12-2025
Robbemans schreef op vrijdag 03 juni 2005 @ 13:55:
Misschien een domme opmerking, maar kun je er geen XML van maken? Hoervoor is zeker een C++ library te vinden...
Ik denk persoonlijk niet dat zoveel overhead gewenst is voor een protocol als dit.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-05 14:03

curry684

left part of the evil twins

Robbemans schreef op vrijdag 03 juni 2005 @ 13:55:
Misschien een domme opmerking, maar kun je er geen XML van maken? Hoervoor is zeker een C++ library te vinden...
XML is nuttig als je interfacet met onbekende partijen op flexibele protocollen. Niet als je een proprietary interface tussen proprietary software legt, dan ben je beter af met een 10 keer zo compact protocol dat je zonder parsen uit kunt lezen etc. :)

DHCP, DNS en zo zijn ook niet voor niets binary protocols ;)

[ Voor 18% gewijzigd door curry684 op 03-06-2005 14:41 ]

Professionele website nodig?


  • dawuss
  • Registratie: Maart 2001
  • Laatst online: 01-02 20:46

dawuss

gadgeteer

Topicstarter
Sowieso moeten deze packets rechtstreeks naar een klein apparaatje gestreamed worden, dus niet over een TCP socket of iets dergelijks.

Het is geen application level protocol, maar eerder een network-level protocol :)

micheljansen.org
Fulltime Verslaafde Commandline Fetisjist ©


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 02-05 01:32
Serilization voor over het netwerk verschilt in niets van serialization van/naar files; het zijn allemaal bytestreams. Je hoeft dus niet specifiek naar netwerk-specifieke dingen te zoeken.

Zelf zou ik, in het netwerkgeval, de serializatie helemaal niet zelf doen maar gewoon CORBA ofzo gebruiken, maar ik begrijp dat dat hier niet helemaal de bedoeling is.

Een goede bron om te beginnen is deze: C++ FAQ lite: Serialization and Unserialization. Het is geen concrete tutorial, maar er staan wel veel zinnige dingen in waarvan het handig is als je er over nadenkt; ik zou je zeker aanraden 'm even door te lezen.

Verder heeft Boost ook een serialization library; misschien kun je daar wat goede ideeën opdoen met betrekking tot ontwerp en implementatie. Daar staan trouwens ook nog links naar andere implementaties.

[ Voor 4% gewijzigd door Soultaker op 03-06-2005 15:43 ]


  • dawuss
  • Registratie: Maart 2001
  • Laatst online: 01-02 20:46

dawuss

gadgeteer

Topicstarter
Soultaker schreef op vrijdag 03 juni 2005 @ 15:41:
Serilization voor over het netwerk verschilt in niets van serialization van/naar files; het zijn allemaal bytestreams. Je hoeft dus niet specifiek naar netwerk-specifieke dingen te zoeken.

Zelf zou ik, in het netwerkgeval, de serializatie helemaal niet zelf doen maar gewoon CORBA ofzo gebruiken, maar ik begrijp dat dat hier niet helemaal de bedoeling is.

Een goede bron om te beginnen is deze: C++ FAQ lite: Serialization and Unserialization. Het is geen concrete tutorial, maar er staan wel veel zinnige dingen in waarvan het handig is als je er over nadenkt; ik zou je zeker aanraden 'm even door te lezen.

Verder heeft Boost ook een serialization library; misschien kun je daar wat goede ideeën opdoen met betrekking tot ontwerp en implementatie. Daar staan trouwens ook nog links naar andere implementaties.
Aan die eerste link heb ik inderdaad al veel gehad, maar dat library was ik nog niet tegen gekomen.

CORBA of iets dergelijks is echt zwaar overkill voor deze toepassing, maar ik heb het wel overwogen ;)

micheljansen.org
Fulltime Verslaafde Commandline Fetisjist ©


  • igmar
  • Registratie: April 2000
  • Laatst online: 20-04 22:06

igmar

ISO20022

.oisyn schreef op vrijdag 03 juni 2005 @ 13:07:
long is minstens 32 bits, als je een 32 bits waarde moet gebruiken heb je aan een long gegarandeerd voldoende, dat was MSalters punt.
Op een 32 bits platform wel ja. Geen idee of dat ook op de 16 bits platformen geld, maar een long kan ook 64 bits zijn.
Je zit alleen nog wel met endianness, maar daar zijn API functies voor (htonl() en ntohl())
Ik geef zelf de voorkeur aan network byte order met versturen, puur omdat de IP stack dat ook doet. Kwestie van voorkeur.

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Als je C++ gebruikt, kijk dan eens naar 'ACE'. Daar zijn ook twee goede boeken over geschreven. (zoek maar op ACE en C++ voor titels op amazon...)

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
long is altijd 32+ bits, op 16,32,64, 36 en 17 bits systemen.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 02-05 01:32
Zoijar schreef op vrijdag 03 juni 2005 @ 17:41:
Als je C++ gebruikt, kijk dan eens naar 'ACE'. Daar zijn ook twee goede boeken over geschreven. (zoek maar op ACE en C++ voor titels op amazon...)
Dat is trouwens ook een CORBA implementatie (en dan nog wat meer); mogelijk dus ook overkill voor de TS. (Wel een erg efficiente implementatie, trouwens.)

[ Voor 3% gewijzigd door Soultaker op 03-06-2005 19:41 ]


  • Eelis
  • Registratie: Januari 2003
  • Laatst online: 21-02-2015
.

[ Voor 99% gewijzigd door Eelis op 18-02-2015 19:07 ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

ACE is idd geen corba; je kan er net zo goed een packet stream mee openen, als een corba object maken. Erg uitgebreide networking lib, en redelijk 'standaard' voor C++.
Pagina: 1