Sockets / Netzwerk: Daten packen?



  • 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 🙂



  • 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 ...


Anmelden zum Antworten