Sockets / Netzwerk: Daten packen?



  • 314159265358979 schrieb:

    char und unsigned char sind beide 1 Byte groß

    Soweit richtig, wenn man vom "C++ Byte" spricht, da der C++ Standard das Wort "Byte" in dieser Weise verwendet.

    (Wertebereich -128 bis 127 bzw 0 bis 255).

    Falsch. Der Wertebereich eines "C++ Bytes" ist vom Standard nicht festgelegt.

    Was deine weiteren Beiträge in diesem Thread angeht: so machst du dir garantiert keine Freunde hier. Wenn ich deinen Nick irgendwo lesen denke ich mir nur mehr "Oh Mann, nicht der schonwieder!".



  • theliquidwave schrieb:

    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.

    Im Prinzip schon.

    1. Nach was muss ich dafür suchen, um ordentliche Implementation zu finden? Oder kennt ihr gar welche?

    Kann dir spontan nur diese Stichworte anbieten: Serialisierung und Wire-Protocol
    Du kannst auch nach allem suchen wo standardisierte File-Formate beschrieben werden, denn die gleichen Anforderungen/Probleme gibt es dort auch. Man möchte ja schliesslich ein JPEG File auch auf einer Plattform lesen, die sich von der unterscheidet mit der es geschrieben wurde. Geht auch, JPEG ist immer JPEG, egal wo's herkommt.

    1. 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.
    1. Es gibt die verschiedensten Standards die den Begriff "Byte" unterschiedlich definieren. C++ sagt ein Byte ist das was an Speicher für ein "char", "signed char" bzw. "unsigned char" gebraucht wird, und es muss min. 256 verschiedene Werte darstellen können. Auf Implementierungen wo ein "char" gleich gross ist wie ein "int", und ein "int" 32 Bit hat, hat dann auch das "C++ Byte" 32 Bit.

    2. Was Netzwerke und Massenspeicher angeht gibt es nur eine de facto Definition von "Byte", und die ist "genau 8 Bit". Wie diese 8 Bit interpretiert werden ist dann wieder eine andere Sache. Kann one's complement oder two's complement sein oder auch ganz was anderes.

    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?

    Ja, das kann sein. Such mal ein wenig zum Thema Serialisierung, da geht's um genau das.
    Beispielsweise kannst du aus deinen Daten XML machen, oder ein anderes Textformat. Diesen Text kannst du dann verschicken, und auf der Gegenseite wieder "parsen", und in die "in memory" Datenstruktur verwandeln. Dabei ist es egal wie gross Integers auf den beiden Seiten sind, so lange alle mindestens so gross sind wie nötig (was du ja sicherstellen kannst). Auch ist es dann egal wenn z.B. der Sender mit one's complement arbeitet, der Empfänger aber mit two's complement.



  • hustbaer schrieb:

    Wenn ich deinen Nick irgendwo lesen denke ich mir nur mehr "Oh Mann, nicht der schonwieder!".

    Weißt du was, das ist mir relativ egal 🙂



  • theliquidwave schrieb:

    [...]

    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.

    So ist es. Die Daten stimmen erst Mal überein. Wenn Du zB 100 Byte gesendet hast, dann liegen die jetzt in identischer Form beim Empfänger vor. Wenn Du beim Sender irgendwo mitten in den 100 Byte einen 4Byte - Integer stecken hast, dann muß der Empfänger natürlich wissen, wo der Integer in den 100 Byte steht, wieviel Byte er belegt, und ob die endianess mit der eigenen übereinstimmt. Anderenfalls ist die Gefahr groß, daß Sender und Empfänger die Daten unterschiedlich interpretieren, und dann geht das schief - es sei denn, die Daten sollen einfach nur angenommen und auf die Platte geschrieben werden. Du brauchst auf jeden Fall ein Protokoll, damit der Empfänger überhaupt erst mal weiß, wieviel Daten er lesen muß. Naja, und wenn er die Daten interpretieren soll, dann muß das Protokoll so gestrickt sein, daß der Empfänger erkennen kann, wo was steht.

    Deshalb wird mancherorts die Empfehlung gegeben, Integer, Floats und vergleichbares in lesbarer Form (Ansi) in einen String zu schreiben und dann zu versenden, aber letztendlich kommt es natürlich immer drauf an, was genau damit gemacht werden soll.



  • Im Netz gibt es kein Vorzeichen mehr, sondern nur noch (zumindest, solange wir uns noch im Softwareteil befinden) einen Strom von Bits.

    Glaub das ist auch nicht ganz korrekt 🙂
    Im Netzt (TCP/IP) ist es ein strom von bytes, wobei bei TCP/IP wie schon erwaehnt, 1 byte aus 8 bits besteht. Unabhaengig von der Ausrichtung, LSB oder MSB (die sollte der TCP/IP Stack auf jedem geraet glattziehen)
    An deinen Endpunkten ist es dann ein Datenstrom aus "Systemspezifischen" Bytes, die den enstprechenden Wert repraesentieren, in jeweils gleicher folge.
    TCP/IP garantiert dir auch nur, dass die byte folgen interpretierbar sind, wenn die geschickten bytes in die definierten 8bit reinpassen, klar.

    1. Definition 1 Byte = 8 Bit -> es gibt Systeme, auf denen die kleinste adressierbare oder verarbeitbare Einheit mehr als 8 Bit umfasst.

    Gibt es das ? denke nocht nicht oder ? aber Zeit wirds bald 🙂
    Glaub die ganze Problematik kommt von der Schiene, wo 1 Byte < 8Bit sind (7Bit gibt es existierende Hardware -> DEC).

    Wenn Du aber den Transportstrom als Folge von Bits siehst, hasst nen Problem, weil er zumindest bei Kommunication 8Bit Maschine zu 7Bit Maschine modifiziert werden wuerde (1 bit immer rausgeworfen, oder 1 bit eingefuegt, je nach Richtung).
    Aber die Kommunikation Funktioniert erwiesener Massen, weil eben einige wichtige Protokolle (die Textbasierten, also html und Co) 7 bit Kompatibel sind. 8Bit basierende Protokolle funktionieren natuerlich nicht.

    @theliquidwave

    2. Daten mit base64 enkodieren

    Genau dafuer ist Base64 eigentlich da 🙂 Binaerdaten über Maschinen schicken, die nur 7bit kompatibel waren (Mail Anhaenge war wohl das populaerste beispiel, da die ganzen alten Mail-Protokolle 7 bit Text kompatibel sein mussten)

    Ob du es nehmen solltes, iss ne andere Frage.

    Viele Formate spezifizieren eigene Definitionen. Da ist die Bytegroesse und ausrichtung, teilweisse sogar abweichend von der Architektur auf der man grad ist, implizit definiert. Dort braeuchtest dich ned auf 7Bit verlassen, sondern kannst 8bitweisse verschicken. Das ne alte DEC das verarbeiten muss, halt ich fuer ausgeschlossen.

    Damit erschlaegst sogar das Endian problem, und kannst dein Format auf eine bestimmte Architektur optimieren 🙂

    Trotzdem ist noch TEXT weitverbreitet in der Netzwerk-kommunication. Laesst sich besser debeuggen (ausspaehen).
    Iss schon klasse, wenn deinen Server mit Telnet ansteuern kannst, und testen 🙂
    Base64 verwendet man auch heutzutage noch, weil grad bei zeilenorientierten Text-Protokollen man damit binaerdaten auch verschicken kann, ohne das irgendwelche textinterpreter wegen 0 und nichtdarstellbaren zeichen ausflippen und mit zeilenende durcheinanderkommen.

    Ciao ...



  • CPUs die keine 8 Bit Stücke direkt adressieren können gibt es schon lange, viele CPUs mit MIPS Architektur z.B.
    Ist aber nicht gerade toll. Macht bloss Code der mit 8 Bit Einheiten arbeiten muss unnötig langsam.

    CPUs mit 7 Bit Bytes sind heute kein Thema mehr.

    Zwei Themen die allerdings immer noch aktuell sind sind Endianness und die verschiedene Breite der C/C++ Datentypen auf verschiedenen Systemen. Und daran wird sich auch in absehbarer Zeit nichts ändern.



  • RHBaum schrieb:

    Im Netzt (TCP/IP) ist es ein strom von bytes[...]

    Dadurch wird die Aussage "Ein Strom von Bits" ja nun nicht falsch. Es sei denn, ein Byte setzt sich nicht aus Bits zusammen. 😉

    RHBaum schrieb:

    Gibt es das ? denke nocht nicht oder ? aber Zeit wirds bald 🙂

    Ja, wie ich bereits oben sagte. Ich habe hier eine Plattform, auf der ist die kleinste adressierbare Einheit 32 Bit groß.
    Da ist sizeof(char) == siezof(int) == sizeof(float) == 1 . Ganz ulkig eigentlich, vor allem, wenn man da nicht drauf achtet.

    RHBaum schrieb:

    Wenn Du aber den Transportstrom als Folge von Bits siehst, hasst nen Problem, weil er zumindest bei Kommunication 8Bit Maschine zu 7Bit Maschine modifiziert werden wuerde (1 bit immer rausgeworfen, oder 1 bit eingefuegt, je nach Richtung).

    Bei sowas ist der Elementtyp des Host-Seitigen Puffers außreichend groß, um ein vollständiges Oktett aufnehmen zu können. Also bei z.B. einem 7-Bittigen char Typen 14 Bit Elementgröße. Oder vielleicht sogar ein Spezialtyp der wirklich 8 Bit groß ist.

    RHBaum schrieb:

    Damit erschlaegst sogar das Endian problem[...]

    Das erschlägt man nur, wenn man in ASCII überträgt. Bei binären Formaten muss man sich immer drum kümmern. Schlimmer wird es noch, wenn man Fließkommazahlen binär übertragen will...

    RHBaum schrieb:

    Trotzdem ist noch TEXT weitverbreitet in der Netzwerk-kommunication. Laesst sich besser debeuggen (ausspaehen).

    Dafür gibt es Verschlüsselung. Verbreitet ist es vor allem deshalb, weil es tatsächlich plattformneutral ist.

    RHBaum schrieb:

    Base64 verwendet man auch heutzutage noch, weil grad bei zeilenorientierten Text-Protokollen man damit binaerdaten auch verschicken kann[...]

    Base64 entbindet einen nicht von dem Problem, von Base64 ist das plattformspezifische Format zu konvertieren. Man gewinnt damit nichts gegenüber einer selbst definierten binären Netzsicht. Bei der Blockzerlegung der Binärdaten zur Konvertierung ins Base64 musst Du Dich auch um die Endianess scheren. Das gleich gilt für die Rückkonvertierung. Die oben angesprochene Problematik bei Fließkommazahlen hat man auch nicht gelöst. Der einzige wirkliche Vorteil ist die Einheitlichkeit.



  • hustbaer schrieb:

    CPUs mit 7 Bit Bytes sind heute kein Thema mehr.

    AFAIK sind char-Größen unter 8 Bit vom Standard nicht unterstützt. Beachte CHAR_BIT aus <climits> was als Minimumwert 8 hat: http://www.cplusplus.com/reference/clibrary/climits/



  • @pumuckl:
    AFAIK hast du damit vollkommen Recht 🙂

    War als Antwort an RHBaum gedacht, weil seine Beitrag so klang als wollte er sagen dass "7 Bit CPUs" irgendwo ein Thema sind, welche die nur > 8 Bit adressieren können aber nicht (weil er meint dass es gar keine gibt).

    Und in Wirklichkeit ist es eben genau andersrum.


Anmelden zum Antworten