C#: Byteweise bis zum Ende des Streams

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von haiyyu.

    C#: Byteweise bis zum Ende des Streams

    Hallo Leute.

    Erstmal muss ich sagen, dass ich weiß, dass das hier ein VB-Forum ist und es daher eigentlich nicht hierher passt.
    Allerdings habe ich in diesem Forum schon einige Leute gesehen, die sich auch gut mit C# auskennen, daher will ich es zuerst hier versuchen, bevor ich mich wo anders anmelde.

    Ich schreibe gerade eine simple Server-Client-Anwendung.
    Dafür verwende ich den TcpClient aus dem System.Net.Sockets-Namespace.

    Das Ganze sieht ungefähr so aus:

    Server:

    C-Quellcode

    1. // ...
    2. TcpClient client = listener.AcceptTcpClient();
    3. BinaryReader reader = new BinaryReader(client.GetStream(), Encoding.ASCII);
    4. while (Running)
    5. {
    6. byte packetId = reader.ReadByte();
    7. List<byte> bytes = new List<byte>();
    8. while (reader.PeekChar() != -1)
    9. {
    10. bytes.Add(reader.ReadByte());
    11. }
    12. if (PacketArrived != null) // Event
    13. PacketArrived(this, new PacketArrivedEventArgs(bytes.ToArray()));
    14. }


    Client:

    C-Quellcode

    1. TcpClient client = new TcpClient();
    2. client.Connect("localhost", 1234);
    3. BinaryWriter writer = new BinaryWriter(client.GetStream());
    4. writer.Write((byte)12);
    5. writer.Write((Int32)3771);
    6. writer.Flush();

    Das Problem ist, dass die 12 am anderen Ende ankommt, jedoch nicht die 3771, da PeekChar() sofort -1 liefert, obwohl doch eigentlich noch etwas im Stream ist, das ausgelesen werden kann.
    Ich habe es alternativ auch schon mit client.Read() am Server probiert, alles Byte für Byte auszulesen, was auch alles schön ausliest, jedoch blockiert die Funktion den Thread, sobald nichts mehr im Stream ist.

    Gibt es eine Möglichkeit, zu überprüfen, ob man am Ende eines Streams angelangt ist? Oder besser noch, was mache ich falsch, so dass PeekChar() nicht funktioniert?
    reader.BaseStream.Length habe ich schon versucht, jedoch wirft mir das eine NotSupportedException, woraus ich schließe, dass das bei Netzwerk-Streams nicht funktioniert (?).

    Würde mich echt freuen, wenn mir jemand helfen könnte. :)

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „haiyyu“ ()

    Hi,

    hast du schon mal versucht, den Stream ohne Reader einzulesen?
    Es gibt im Stream eine ReadByte-Funktion, die -1 zurückgibt, wenn das Ende erreicht wurde:
    msdn.microsoft.com/en-us/libra…m.io.stream.readbyte.aspx

    Einfach in 'nen int reinhauen und je nachdem, ob's größer als -1 ist oder nicht, nach 'nem Byte casten.

    reader.BaseStream.Length gibt es wohl nicht, da ein NetworkStream ja eine "dynamische" Länge hat. Bei FileStreams z.B. gibt es sowas (das ist dann die Dateigröße in Bytes).

    Was ist, wenn du den Flush weg lässt?
    Von meinem iPhone gesendet

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „nikeee13“ ()

    Danke für den Tipp.

    Leider passiert das Selbe wie bei BinaryReader.Read()...
    Die Bytes, die im Stream sind, werden problemlos ausgelesen, danach blockiert die Funktion jedoch.
    Sie gibt also kein -1 zurück, sondern wartet, bis was Neues kommt.

    Das mit dem Flush probiere ich jetzt.

    Edit: Keinen Unterschied ohne Flush. Aber... ich dachte, Flush() sei dafür da, dass das Ganze gesendet wird?
    Gibt es überhaupt eine Flush-Methode im TcpClient? Oder meinst du mit client 'ne art Streamwriter (Binarywriter?)?
    Ja, soweit ich weiß ist diese Methode dafür da, aber man kann ja nie wissen. ;)

    Ich befürchte, dass der NetworkStream kein eigentliches Ende hat (aus dem gleichen Grund, warum er keine feste Länge hat).
    Von meinem iPhone gesendet
    Uh, verdammt.
    Da hab ich mich wohl beim Abtippen vertan.

    Hab's oben gefixt (Client-Code). Sorry. : - /

    Also: Ja, ich verwende einen BinaryWriter, um in den Stream zu schreiben.
    Hm, vielleicht solltest du so arbeiten, dass als erstes ein (u)Int(64?) die Anzahl der Bytes im Stream angibt. Damit du aufhören kannst, sobald du diese Anzahl an Bytes eingelesen hast. Dann wird der Thread nicht mehr blockiert und du kannst weiter machen.
    Was anderes fällt mir gerade auch nicht ein.

    Wenn du eine andere Lösung findest, würde sie mich wirklich interessieren. :)
    Von meinem iPhone gesendet
    Jo, wird wohl das Einzige sein, was mir im Moment übrig bleibt.
    Ich werd mich trotzdem nochmal umschauen. Schließlich muss das ja irgendwie anders gehen. :/

    Aber danke für die Hilfe. :)
    msdn.microsoft.com/de-de/libra…am.read%28v=vs.80%29.aspx
    Die Gesamtanzahl der in den Puffer gelesenen Bytes. Dies kann weniger als die Anzahl der angeforderten Bytes sein, wenn diese Anzahl an Bytes derzeit nicht verfügbar ist, oder 0, wenn das Ende des Streams erreicht ist.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Selbes Ergebnis wie bei Read()... :( Blockiert...

    Btw., das Thema ist nicht erledigt, bin versehentlich auf den Knopf gekommen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „haiyyu“ ()

    orly, ich dachte das hab ich immer verwendet...xD

    Na dann gehts vlt. direkt mit den Socket-Funktionen besser, ist sowieso schöner BeginReceive/Read oder so zu verwenden :P
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Jo... ich find's ein wenig komisch, dass das nicht geht. :/

    Normalerweise hab ich's immer so gemacht, dass ich je nach Paket-ID die entsprechenden Parameter ausgelesen habe, was sich immer perfekt ausging.
    Jetzt jedoch will ich alles auslesen, was da ist, und es "weiterleiten". Nur daran scheiterts.
    Weil ich ihn später noch brauchen werde... das, was ich hier gepostet hab, war ja nur ein kleiner Ausschnit vom Code.
    Flush() leert den Buffer und schreibt das, was drin ist, in den Stream. (...zumindest sollte es das)

    Der Server lauscht die ganze Zeit.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „haiyyu“ ()

    Ist es Möglich, dass du Read falsch anwendest?
    Sobald nämlichder zurückgegebene Int < Puffer, ist fertiggelesen... dann brauchst du nicht nochmal aufrufen, sonst ist klar, dass es blockiert...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Hi.

    Ich habe mir das Problem mal angeschaut, konnte es aber nicht so ganz nachvollziehen...
    Daher habe ich mal ein Beispiel gemacht, wie ich denke das es funktionieren würde.
    Eventuell kannst du das Problem nochmal näher beschreiben...

    VB.NET-Quellcode

    1. class Server
    2. {
    3. private TcpListener srv;
    4. private Thread lThread;
    5. public Server()
    6. {
    7. this.srv = new TcpListener(IPAddress.Any, 3000);
    8. this.lThread = new Thread(new ThreadStart(listen));
    9. this.lThread.Start();
    10. }
    11. void listen()
    12. {
    13. this.srv.Start();
    14. //hier müsste man noch eine Abruchbedingung einbauen...
    15. while (true)
    16. {
    17. //Einen Client akzeptieren
    18. TcpClient client = this.srv.AcceptTcpClient();
    19. //Client Thread erzeugen
    20. //Als Parameter der Client
    21. Thread clientThread = new Thread(new ParameterizedThreadStart(ClientComm));
    22. clientThread.Start(client);
    23. }
    24. }
    25. private void ClientComm(object client)
    26. {
    27. TcpClient tcpClient = (TcpClient)client;
    28. // Stream holen
    29. NetworkStream clientStream = tcpClient.GetStream();
    30. byte packetId;
    31. List<byte> bytes;
    32. while (true)
    33. {
    34. try
    35. {
    36. //PacketId lesen
    37. packetId = (byte) clientStream.ReadByte();
    38. //List cleanen
    39. bytes = new List<byte>();
    40. //Solange noch Daten folgen, diese an ByteListe hängen
    41. while (clientStream.DataAvailable)
    42. {
    43. bytes.Add((byte) clientStream.ReadByte());
    44. }
    45. }
    46. catch
    47. {
    48. //Disconnect etc, ist hier im BSP nicht weiter behandelt
    49. System.Diagnostics.Debug.WriteLine("Socket Fehler");
    50. break;
    51. }
    52. //Nachricht angekommen.
    53. //Ausgabe PacketId und alle angekommenen Bytes
    54. System.Diagnostics.Debug.WriteLine("packetId: " + packetId.ToString());
    55. for (int a = 0; a < bytes.Count; a++)
    56. System.Diagnostics.Debug.WriteLine(a + ". tes Byte: " + bytes[a].ToString());
    57. }
    58. tcpClient.Close();
    59. }
    60. }
    Das ist meine Signatur und sie wird wunderbar sein!
    jvbsl: Ich springe aus der Schleife raus, sobald der Wert Rückgabe < Puffer, daher wird es nicht nochmal aufgerufen.
    Mono: Ich versuch es mal so. DataAvailable habe ich noch nicht probiert. Wenn das auch nicht geht, habe ich irgendwo einen Logikfehler drin, denke ich. Danke. :)

    Edit:

    Ich glaub's nicht. Das hat funktioniert. :)
    Wird alles schön empfangen und blockiert auch nicht, wenn er fertig ist.
    Nachdem alles da ist, wartet der Server brav auf das nächste Paket.

    Dankesehr!

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „haiyyu“ ()