Sockets / Netzwerk: Daten packen?



  • Ich habe vor einiger Zeit mal auf einer Seite zum Thema Socketprogrammierung gelesen, dass es ratsam ist, die Daten vorm Senden zu packen und entsprechend wieder zu entpacken. Damit gemeint ist keinesfalls eine Komprimierung, sondern eher der "Fix" des Problems, dass verschiedene Typen auf verschiedenen System verschiedene Größen haben.

    So kann ich mich noch daran erinnern, dass der Autor des Tutorials geschrieben hat, dass es oft zu Problemen kommt, weil beispielsweise ein Client von einer anderen Integer oder Float Größe ausgeht als der Server.

    Er hat deshalb eine kleine Ansammlung von Funktionen bereitgestellt, um das ganze zu machen. Allerdings ist die Implementation nicht gut gelungen, und sie ist in C geschrieben.

    Deshalb einige Fragen:

    1. Stimmt das ganze so überhaupt? Ich könnte mir es jedenfalls gut vorstellen.
    2. Nach was muss ich dafür suchen, um ordentliche Implementation zu finden? Oder kennt ihr gar welche?
    3. Ist ein "Byte" eigentlich definiert von 0 bis 128 oder von 0 bis 255? Weil ich in einigen Tutorials immer wieder unsigned char* sehe, die gesendet werden; andere sagen widerrum, dass ein char* verwendet werden muss. Was stimmt nun? Zumindest die send Funktion nimmt nur einen char* an.

    Gruß und Danke



  • char und unsigned char sind beide 1 Byte groß (Wertebereich -128 bis 127 bzw 0 bis 255).
    Worauf du achten musst ist vor allem der Byte-Order. (Das heißt die Reihenfolge, in der du die einzelnen Bytes sendest)

    Ja, du musst die Daten in einen char* bekommen.



  • 314159265358979 schrieb:

    char und unsigned char sind beide 1 Byte groß (Wertebereich -128 bis 127 bzw 0 bis 255).

    Das stimmt nicht. Ich arbeite hier mit einer Plattform, da ist ein char 4 Byte (Oktette) groß. Auf dieser Plattform ist sowohl sizeof(int) als auch sizeof(char) 1. Wieviele Bits ein char tatsächlich hat, lässt sich über CHAR_BIT aus <climits> oder std::numeric_limits<unsigned char>::digits aus <limits> herausbekommen.



  • Ein char ist per Definition 1 Byte groß.



  • 314159265358979 schrieb:

    Ein char ist per Definition 1 Byte groß.

    Der Standard garantiert nur, dass ein char _mindestens_ ein Byte groß ist.
    Also darf ich tatsächlich nur Bytes von 0 bis 127 senden?



  • 314159265358979 schrieb:

    Ein char ist per Definition 1 Byte groß.

    Nein. sizeof(char) liefert per Definition 1. Das ist aber nicht gleichbedeutend mit 1 Byte. char muss außreichend groß sein, um das sogenannte "Basic Character Set" der unterliegenden Compilerimplementierung fassen zu können. Das ist aber auch schon alles, was spezifiziert ist.



  • Nein, er ist exakt 1 Byte groß. Nicht mehr und nicht weniger.



  • Ev. könnte es sein, dass 1 Byte nicht (edit: immer) 8 bits gross ist?



  • Davon war nie die Rede, Klugscheißer.



  • Uhh.. heute bist Du aber höflich unterwegs... 🕶



  • theliquidwave schrieb:

    Also darf ich tatsächlich nur Bytes von 0 bis 127 senden?

    Das wär ja traurig. Selbstverständlich darfst Du senden, was immer Du willst.



  • Das verstehe ich nun gar nicht mehr. Per Definition geht ein char doch von -127 bis 128 bzw. von 0 bis 255. Und wenn ich dann doch von 0 bis 255 darf, wieso nimmt die send-Funktion dann nur einen char*?



  • 314159265358979 schrieb:

    Davon war nie die Rede, Klugscheißer.

    Doch, denn das ist sehr wichtig, wenn man ein plattformneutrales Übertragungsprotokoll haben will.

    1. Stimmt das ganze so überhaupt? Ich könnte mir es jedenfalls gut vorstellen.
      Wenn Du meinst, dass Du Deine Daten, um plattformneutral zu sein, in ein unabhängiges Format konvertieren musst: Ja, das ist so korrekt.

    2. Nach was muss ich dafür suchen, um ordentliche Implementation zu finden? Oder kennt ihr gar welche?
      Es gibt eine Unterscheidung "Host Byte Order" und "Network Byte Order". Wichtig ist, die "Network Byte Order" festzulegen, und dann entsprechend zu konvertieren. Viele Socket-APIs bieten hierfür Funktionen an. Zum Beispiel htonl und ntohl . Außerdem ist die Bytegröße bei IP mit 8 Bit festgelegt. Wie die Socket-API mit den Daten umgeht, die man Ihr übergibt, hängt von der Implementierung ab. Die oben von mir genannte Plattform erwartet in ihrer API ein char-Array, wobei von jedem Element nur 8 Bit ausgehend vom LSB versendet werden.
      Wenn die Software nicht absolute zeitkritisch ist, dann bietet es sich an, Daten ASCII-Codiert zu übertragen. Damit erledigen sich viele Probleme (vor allem die Endianess betreffend) von selbst.

    3. Ist ein "Byte" eigentlich definiert von 0 bis 128 oder von 0 bis 255? Weil ich in einigen Tutorials immer wieder unsigned char* sehe, die gesendet werden; andere sagen widerrum, dass ein char* verwendet werden muss. Was stimmt nun? Zumindest die send Funktion nimmt nur einen char* an.
      Ein Byte ist nicht zwangsläufig 8 Bit groß. Ein 8-Tupel aus Bits ist genaugenommen ein Oktett. Ein Byte kann auch weniger oder mehr als 8 Bit haben. Allerdings ist es heutzutage allgemeiner Konsens, dass ein Byte = 8 Bit sind.
      Im Netz gibt es kein Vorzeichen mehr, sondern nur noch (zumindest, solange wir uns noch im Softwareteil befinden) einen Strom von Bits.



  • Warum werden mir immer Dinge angedichtet, die ich nicht gesagt habe? Ich habe nie gesagt, dass das unwichtig wäre, ich habe nur gesagt, dass davon nicht die Rede war -.-



  • Ich gabe zwar zu, es ist albern so krümelkackerisch zu sein aber:

    314159265358979 schrieb:

    Davon war nie die Rede, Klugscheißer.

    314159265358979 schrieb:

    char und unsigned char sind beide 1 Byte groß (Wertebereich -128 bis 127 bzw 0 bis 255).



  • Ich habe nicht behauptet, dass dem immer so ist, nur im Normalfall.



  • 314159265358979 schrieb:

    Davon war nie die Rede, Klugscheißer.

    Vorab erstmal: mäßige dich bitte im Ton und bleib sachlich.

    Dann: du hast in einem Schwung von einem Byte und dem Wertebereich 0 bis 255 bzw. -127 bis 128 geschrieben.

    Der Wertebereich ist schonmal falsch, wenn ein [signed|unsigned] char mehr als 8 Bit belegt.

    Ob ein char jetzt immer exakt ein Byte groß ist oder mehrere Byte groß sein kann ist von der Definition des Byte abhängig. Wenn man den Byte als die Größe des char-Datentyps definiert stimmts natürlich. Nimmt man eine andere Definition, stimmts eben nicht unbedingt. Beispiel:

    1. Definition 1 Byte = 8 Bit -> es gibt Systeme, auf denen die kleinste adressierbare oder verarbeitbare Einheit mehr als 8 Bit umfasst.
    2. Definition 1 Byte = kleinste adressierbare/verarbeitbare Dateneinheit -> Es gibt Compiler für Systeme, deren kleinste Einheit zwar 8 Bit beträgt, die aber trotzdem 16 Bit zu einem char zusammenfassen
      ein google nach "define:Byte" liefert haufenweise unterschiedliche Ergebnisse - ne allgemeingültige Definition gibts wohl nicht.


  • theliquidwave schrieb:

    Das verstehe ich nun gar nicht mehr. Per Definition geht ein char doch von -127 bis 128 bzw. von 0 bis 255. Und wenn ich dann doch von 0 bis 255 darf, wieso nimmt die send-Funktion dann nur einen char*?

    Das sind nur die Definitionen der Wertebereiche, die abhängig davon sind, ob man den char als vorzeichenlos oder vorzeichenbehaftet betrachtet, also nur eine Interpretationsfrage.

    Die send-Funktion sendet die 8 bit, auf die char* zeigt (und bei Bedarf auch die weiteren dahinterliegenden 8bit - Werte.

    Diese 8bit dürfen jede beliebige Kombination aufweisen, also 256 verschiedene Möglichkeiten. Wenn Du dann die 8bit (den char) als vorzeichenbehafteten Integer interpretierst, dann geht sein Wertebereich halt von -128 bis 127, wenn Du ihn als vorzeichenlosen Integer interpretierst, reicht der Wertebereich von 0 bis 255.

    Wenn Du zB ein jpg - Bild, oder einen Text versendest, dann interessiert Dich diese Art der Betrachtung gar nicht ...



  • pumuckl schrieb:

    314159265358979 schrieb:

    Davon war nie die Rede, Klugscheißer.

    Vorab erstmal: mäßige dich bitte im Ton und bleib sachlich.

    Dann: du hast in einem Schwung von einem Byte und dem Wertebereich 0 bis 255 bzw. -127 bis 128 geschrieben.

    Lern lesen, danke sehr.



  • Ach so, ich glaube jetzt verstehe ich das ganze. Angenommen, ich mache folgendes - wäre das so "akzeptabel"?

    1. Daten verschlüsseln (z.B. AES o.Ä.)
    2. Daten mit base64 enkodieren
    3. Daten senden

    ...

    4. Daten empfangen
    5. Daten mit base64 dekodieren
    6. Daten entschlüsseln

    So. Nun habe ich die Daten (hoffentlich korrekt) angenommen. Das heißt, dass die Daten auf dem Client und dem Server jetzt ABSOLUT übereinstimmen, richtig?

    Problem ist nun aber, dass ich nicht davon ausgehen kann, nur ASCII Zeichen zu versenden (ergo Strings), sondern möchte ich ja auch int, bool, float, usw. senden.

    Es könnte doch nun sein, dass beim Client sizeof(int) == 4 ist, und beim Server sizeof(int) == 8. Dann würde mein Vorgehen doch eben fehlschlagen, da der Client eben nur 4bytes gesendet hat, der Server aber 8bytes erwartet. Dass muss ich doch irgendwie packen, oder? Den aus meinem ersten Post angesprochenen Code findet ihr hier: http://pastebin.com/L7VLZi3A

    Ich hoffe ich habe das jetzt verständlich erklärt 🙂


Log in to reply