2009-03-14 10 views
4

lässt sagen, wir haben ein binäres Protokoll, mit Feldern Netzwerk geordnet (Big Endian).binäres Protokoll - Byte Swap-Trick

struct msg1 
{ 
    int32 a; 
    int16 b; 
    uint32 c 
} 

wenn anstelle des Kopierens der Netzwerkpuffer auf meine msg1 und dann die „networkToHost“ Funktionen verwenden msg1

I neu ordnen/Rückwärts-msg1 zu

struct msg1 
{ 
    uint32 c 
    int16 b; 
    int32 a; 
} 

zu lesen und zu tun, einfach eine umgekehrte Kopieren Sie aus dem Netzwerkpuffer, um msg1 zu erstellen. In diesem Fall sind keine networkToHost-Funktionen erforderlich. Dieser idiomatische Ansatz funktioniert nicht in Big-Endian-Maschinen, aber für mich ist das kein Problem. Abgesehen davon, gibt es einen anderen Nachteil, den ich vermisse?

danke

P.S. Für das oben genannte erzwingen wir strenge Ausrichtung (#pragma pack(1) usw.)

+0

FYI: Sie können den Code besser formatieren, indem Sie alles auswählen und STRG + K drücken. – JaredPar

+1

Beachten Sie, dass #pragma pack (1) auf vielen Computern keine Bedeutung hat. –

Antwort

6

Sind Sie sicher, dass dies erforderlich ist? Wahrscheinlich ist Ihr Netzwerkverkehr eher Ihr Engpass als die CPU-Geschwindigkeit.

2

Je nachdem, wie Ihr Compiler die Bytes innerhalb einer Struktur packt, wird die 16-Bit-Zahl in der Mitte möglicherweise nicht an der richtigen Stelle enden. Es kann in einem 32-Bit-Feld gespeichert werden und wenn Sie die Bytes umkehren, wird es "verschwinden".

Im Ernst, Tricks wie diese scheinen niedlich, wenn Sie sie schreiben, aber auf lange Sicht sind sie einfach nicht wert.

bearbeiten

Sie haben die „Pack 1“ -Informationen so der Fehler geht weg, aber die Sache über „nette Tricks“ steht immer noch - es nicht wert. Schreiben Sie eine Funktion, um 32-Bit- und 16-Bit-Zahlen umzukehren.

inline void reverse(int16 &n) 
{ 
    ... 
} 

inline void reverse(int32 &n) 
{ 
    ... 
} 
+0

danke für deine Antworten Jungs. lassen Sie mich ein bisschen mehr erklären: 1) der Trick ist nur für eingehende Nachrichten, lesen Sie die Nachricht und konstruieren etwas nützlich für meine Anwendung 2) Der Grund, warum ich das tat war nicht Leistung, ich hasse nur GETers, dass würde Umwandlung in Host-Reihenfolge machen –

+0

Schreiben Sie keine Funktion. Verwenden Sie ntohs, ntohl, htons und htonl. Sie existieren bereits. – jmucchiello

+0

@joe_mucchiello, Vielleicht können diese Überschreibungen ntohs und ntohl aufrufen. Ich würde sie persönlich "networkToHost" oder so nennen und sie einen Wert zurückgeben, anstatt auf einer Referenz zu arbeiten. – strager

5

Vereinbaren Sie mit @ribond -

Dieses hat ein großes Potenzial für Entwickler sehr verwirrend zu sein, weil sie arbeiten müssen, werden trennen diese semantisch identische Strukturen zu halten.

Da die Netzwerklatenz in der Größenordnung von 10.000.000x langsamer ist als die CPU, um sie zu verarbeiten, würde ich sie einfach beibehalten.

20

Abgesehen davon, gibt es einen anderen Nachteil, den ich vermisse?

Ich fürchte, Sie haben die Art der Endian Conversion-Probleme missverstanden. "Big Endian" bedeutet nicht, Ihre Felder werden in umgekehrter Reihenfolge angelegt, so dass ein

struct msg1_bigendian 
{ 
    int32 a; 
    int16 b; 
    uint32 c 
} 

auf einer Big-Endian-Architektur zu einem

entsprechen
struct msg1_littleendian 
{ 
    uint32 c; 
    int16 b; 
    int32 a; 
} 

auf einer Little-Endian-Architektur. Es bedeutet vielmehr, dass die Byte-Reihenfolge innerhalb jedes Feld umgekehrt ist.Nehmen wir an:

a = 0x1000000a; 
b = 0xb; 
c = 0xc; 

Auf einem Big-Endian-Architektur, wird dies als verlegt werden:

10 00 00 0a 
00 0b 
00 00 00 0c 

Die hohe Ordnung (höchstwertigen) Byte an erster Stelle.

0a 00 00 10 
0b 00 
0c 00 00 00 

Die niedrigste Byte zuerst kommt, die höchste Ordnung letzte:

Auf einer Little-Endian-Maschine, wird dies als verlegt werden.

serialisiert sie und überlagern die serialisierte Form der Nachrichten auf der jeweils anderen, und Sie werden die Inkompatibilität entdecken:

10 00 00 0a 00 0b 00 00 00 0c (big endian) 
0a 00 00 10 0b 00 0c 00 00 00 (little endian) 

    int32 a int16 b int32 c 

Beachten Sie, dass dies nicht einfach ein Fall der Felder läuft in umgekehrter Richtung. Ihr Vorschlag würde dazu führen, dass ein kleines Endian-Gerät die Big-Endian-Darstellung wie folgt interpretiert:

a = 0xc000000; b = 0xb00; c = 0xa000010;

Sicher nicht was übertragen wurde!

Sie müssen wirklich jedes einzelne Feld in Netzwerk-Byte-Reihenfolge und wieder zurück konvertieren, für jedes übertragene Feld.

UPDATE:

Ok, ich verstehe, was Sie jetzt zu tun versuchen. Sie möchten die Struktur in umgekehrter Reihenfolge definieren, dann memcpy von Ende der Byte-Zeichenfolge an den Anfang (umgekehrte Kopie) und umgekehrt die Byte-Reihenfolge auf diese Weise. In diesem Fall würde ich sagen, ja, das ist ein Hack, und ja, es macht Ihren Code unportierbar, und ja, es ist es nicht wert. Das Konvertieren zwischen Byte-Ordnungen ist in der Tat keine sehr teure Operation, und es ist viel einfacher, damit umzugehen, als das Layout jeder Struktur umzukehren.

0

Bitte tun Sie den Programmierern, die nach Ihnen einen Gefallen tun und schreibe explizite Konvertierungen in und aus einer Folge von Bytes in einem Puffer. Trickserei mit Strukturen führt dich direkt in die Endian- und Alignment-Hölle (war dort).

1

Wenn Sie nicht nachweisen können, dass eine erhebliche Leistungseinbuße vorliegt, sollten Sie den gleichen Code verwenden, um Daten unabhängig von der Endian-Ness des Rechners auf das Netzwerk und vom Netzwerk zu übertragen. Als Optimierung können Sie für die Plattformen, bei denen die Netzwerkreihenfolge der Hardware-Byte-Reihenfolge entspricht, Tricks verwenden, aber beachten Sie die Ausrichtungsanforderungen und Ähnliches.

In diesem Beispiel benötigen viele Maschinen (besonders Big-Endian) ein 2-Byte Pad zwischen dem Ende des int16-Members und dem nächsten int32-Member. Obwohl Sie also in einen 10-Byte-Puffer lesen können, können Sie diesen Puffer nicht als Abbild der Struktur behandeln, die auf den meisten Plattformen 12 Byte beträgt.

1

Wie Sie sagen, ist dies nicht auf Big-Endian-Maschinen übertragbar. Das ist ein absoluter Deal-Breaker, wenn Sie jemals erwarten, dass Ihr Code außerhalb der x86-Welt verwendet wird. Tun Sie den Rest von uns einen Gefallen und verwenden Sie einfach die NTOH/HTON-Routinen oder Sie werden wahrscheinlich auf thedailywtf irgendwie vorgestellt werden.