Mehrfaches schreiben in den Stream

  • C#
  • .NET (FX) 4.0

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von EaranMaleasi.

    Mehrfaches schreiben in den Stream

    Hey, Leute,
    ich bin ja seit einiger Zeit an einer Verschlüsselten Netzwerkübertragung dran.
    Nun jedoch habe ich ein grundlegendes (Verständnis-)Problem was das Senden und Empfangen von Daten angeht. Es kommt gelegentlich vor, dass eine Seite der Verbindung zwei mal direkt nacheinander etwas in den Stream schreiben muss, und auf der anderen Seite folglich zwei Mal gelesen werden muss. Da kann es nun vorkommen, dass die Empfängerseite zu langsam ist, und so anstatt separat 320 und 336 Bytes, auf einmal 656 Bytes erhält. Ist es hierbei wirklich die beste Methode die Empfängerseite zuerst eine winzige Nachricht zurück schicken zu lassen, die der Sender lesen muss? Oder gibt es da etwas Eleganteres?
    Das mit der Anzahl Bytes habe ich so umgangen:

    C#-Quellcode

    1. byte[] ReadBuffer = null;
    2. byte[] ExactText = null;
    3. while(read)
    4. {
    5. ReadBuffer = new byte[2048]; //jede Runde neu zugewiesen da sonst Fehler aufgetreten sind
    6. byte[] ExactText = null; //das gleiche
    7. stream.Read(ReadBuffer, 0, ReadBuffer.Length);
    8. stream.Write(new byte[1], 0, 1);
    9. //Der Gegenüber liest exakt ein byte nachdem er Etwas gesendet hat, dadurch wird sichergestellt,
    10. //dass er nicht ein zweites Mal in den stream schreibt, bevor nicht dieser hier den stream gelesen hat.
    11. Array.Reverse(ReadBuffer);//umdrehen des Puffers
    12. ExactText = ReadBuffer.SkipWhile(x => x == 0).ToArray();//schrieben des inhalts des puffers, ohne nullen
    13. Array.Reverse(ExactText);//umdrehen der Daten
    14. //Entschlüsselung...
    15. //Encodierung / Umwandlung von Bytes in was auch immer
    16. }

    Warum den Puffer umdrehen? da bei mir seltsamerweise, das ganze nur so Funktioniert hat.
    Mein Puffer ist mit 2kB bei weitem größer als das Größte was ich bisher verschicken musste, was so um die 500 Bytes waren.
    Jedoch kann in zukunft das Datenaufkommen etwas steigen, da ich nicht nur 250 Zeichen lange Strings verschicken möchte(das war nahe der Grenze mit RSA 3128, jetzt wird mit AES verschlüsselt). Und achja, nachdem die Daten durch sind, Schicke ich noch einen "End-String" mit dem der gegenüber weiß, dass er nun nicht mehr lesen muss. wäre hier mit stream.DataAvailable möglich das ganze effizienter zu gestalten? Jedes Byte, dass ich über den Stream schicke ist in meinen Augen eine enorme Fehlerquelle mehr, weswegen ich so wenig wie nur möglich schicken möchte.
    also das mit dem AntwortByte schreiben halte ich für Quatsch. Das mit dem umgedrehten Buffer versteh ich auch nicht.


    Mal neuer Ansatz: Setz einen CryptoStream auf einen Networkstream, nimm einen BinaryFormatter und serialisiere deine Objekte in den Cryptostream - gesendet ist.
    Empfänger entsprechend.

    Da musst du nichtmal mehr mitteilen, wieviele Bytes nu gesendet werden - kümmert sich alles der BinaryFormatter drum.

    (glaub ich - probiert hab ich das noch nicht)
    CryptoStream... da hab ich schon meine Erfahrungen mit gesammelt, und die waren nicht gerade Rosig.
    Seitdem Hangel ich mich da Manuell durch und bisher klappt es auch ganz gut.

    Ich werde mich dennoch mal bei Gelegenheit ein weiteres mal an den CryptoStream setzen und versuchen deinen Vorschlag umzusetzen. Derzeit habe ich leider keine Zeit viel daran zu Arbeiten, werde jedoch mich Daheim mal daran versuchen.

    Das Antwort-Byte diente als "Vollschreibschutz". so kann der Gegenüber erst wieder schrieben, wenn er das byte gelesen hat. Damit ist sichergestellt dass der Empfänger die erste Nachricht ausm stream gelesen hat.

    Das Umdrehen des Buffers? Anders wollten sich die zwischen 1500 und 1680 leeren bytes nicht entfernen lassen, bzw. nicht, nicht in ExactText Speichern lassen. Ich hatte immer volle 2kb, anstatt der gewünschten 320 byte.

    Edit: Okay, dann werde ich es heute Abend Daheim auch mal Testen und Versuchen auf den Stand zu bringen, den ich hier benötige.
    ​Das Umdrehen des Buffers? Anders wollten sich die zwischen 1500 und 1680 leeren bytes nicht entfernen lassen, bzw. nicht, nicht in ExactText Speichern lassen. Ich hatte immer volle 2kb, anstatt der gewünschten 320 byte.


    Deswegen meinte EDR du solltest einen Header schicken der angibt, wieviel gelesen werden soll. Außerdem ist dieses Check Byte unnötig, der sich die Daten im Stream ansammeln, und er eh erst die erste Nachricht lesen muss. Ein Header wär also neben Serialisierung die beste Variante.

    EaranMaleasi schrieb:

    Damit ist sichergestellt dass der Empfänger die erste Nachricht ausm stream gelesen hat.
    wie gesagt: sowas sind Protokoll-Fragen. Prinzipiell ist schnurz, ob der Empfänger die vorherige Nachricht gelesen hat. Die aktuelle Nachricht kann er nicht eher lesen, als er die vorherige abgearbeitet hat.
    Um solch Feinheiten kümmert sich der Networkstream.
    So nu hab ich mich endlcih mal rangesetzt an die sache mit dem CryptoStream und dem BinaryFormatter, und was ist natürlich? ich stehe damit noch immer auf dme Kriegsfuß, und das, wo doch der BinaryFormatter mit seinem Header mir einen guten dienst leisten würde. Doch will es bei mir nun mal überhaupt nicht funktionieren. ich hatte zuerst alles aufgebaut mit dne ganzen HEadern usw. und nun alles aufs mindeste reduziert:

    C#-Quellcode

    1. using(RijndaelManaged aes = new RijndaelManaged() { KeySize = 256, BlockSize = 256, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 })
    2. {
    3. aes.Key = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
    4. aes.IV = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
    5. using(CryptoStream cs = new CryptoStream(stream, aes.CreateEncryptor(), CryptoStreamMode.Read))
    6. {
    7. try
    8. {
    9. BinaryFormatter bf = new BinaryFormatter();
    10. object c = bf.Deserialize(cs);
    11. return true;
    12. }
    13. catch(Exception)
    14. {
    15. return false;
    16. }
    17. }
    18. }

    Key und IV werden später mit richtigen Schlüsseln/zufälligen bytes versehen, der einfachheit halber wollte ich es nun mal so gestalten.

    Das Senden wäre dann so:

    C#-Quellcode

    1. using(RijndaelManaged aes = new RijndaelManaged() { KeySize = 256, BlockSize = 256, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 })
    2. {
    3. aes.IV = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
    4. aes.Key = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
    5. using(CryptoStream cs = new CryptoStream(stream, aes.CreateEncryptor(), CryptoStreamMode.Write))
    6. {
    7. try
    8. {
    9. BinaryFormatter bf = new BinaryFormatter();
    10. bf.Serialize(cs, Message);
    11. return true;
    12. }
    13. catch(Exception)
    14. { return false; }
    15. }
    16. }

    Das Senden funktioniert soweit ganz gut, beim Deserialisieren bekomme ich jedoch die Meldung:
    Der binäre Datenstrom "187" enthält keinen gültigen BinaryHeader. Möglicherweise ist der Datenstrom ungültig oder die Objektversion wurde zwischen der Serialisierung und der Deserialisierung geändert.
    Vor der Vereinfachung habe ich ähnliche Fehlermeldungen bekommen, dass der stream den falschen BinaryTyp hätte oder so ähnlich mit der aufzählung der erstzen bytes.

    Edit: Einen Fehler habe ich nun selbst entdeckt... man sollte eben einen Encryptor UND Decryptor benutzen...
    Jedoch friert mir der lesende beim Deserialize schlichtweg ein... und einen Header sowie Headerhandler hinzuzufügen resultiert direkt wieder in der genannten exception.

    Edit 2:
    Nun hat sich das Problem soweit gelöst, ich kann auf einem Network-Stream über den BinaryFormatter schreiben, und auch Header entsprechend ver-/bearbeiten. Sobald ich noch die Verschlüsselung geregelt habe, werde ich hier die Lösung des Ganzen posten

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „EaranMaleasi“ ()