Laden...

NetworkStream.DataAvailable - Verständnisfrage

Erstellt von srynoname vor 14 Jahren Letzter Beitrag vor 14 Jahren 5.386 Views
S
srynoname Themenstarter:in
223 Beiträge seit 2006
vor 14 Jahren
NetworkStream.DataAvailable - Verständnisfrage

Hallo,

ich habe folgenden Code:

            TcpClient tcpclient = new TcpClient("127.0.0.1", 143); //use beginconnect
            NetworkStream stream = tcpclient.GetStream();
            
            byte [] buffer = new byte[2048];

            StringBuilder messageData = new StringBuilder();

            int bytes = -1;

            //Thread.Sleep(1000);

            while (stream.DataAvailable)
            {
                bytes = stream.Read(buffer, 0, buffer.Length);
               
                // Use Decoder class to convert from bytes to UTF8 
                // in case a character spans two buffers. 
                Decoder decoder = Encoding.UTF8.GetDecoder();
                char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
                decoder.GetChars(buffer, 0, bytes, chars, 0);

                messageData.Append(chars);
            }


            MessageBox.Show(messageData.ToString());

Dabei passiert meiner Meinung nach etwas ganz merkwürdiges:
Führe ich das ganze so aus, erhalte ich in der Messagebox keine Ausgabe.
Kommentiere ich dagegen Thread.Sleep(1000) aus (oder nutze den Debugger und gehe das ganze per Einzelschritt durch, was ja auch wieder eine Zeitverzögerung darstellt), dann erhalte ich die gewünschte Ausgabe.
Ich verstehe nur nicht, warum? Es handelt sich hierbei ja um sequentielle Aufrufe, nicht um parallele oder so.

In der MSDN wird NetworkStream.DataAvailable immer per do while Schleife verwendet, damit geht es dann auch bei mir. Aber mit der do while Schleife habe ich doch das Problem, das der erste Durchlauf der Schleife immer stattfindet, ohne das ich weiß, ob Daten zum Lesen verfügbar sind!? Deswegen wollte ich eigentlich eine normale while Schleife nutzen, die finde ich irgendwie auch übersichtlicher.

Kann mir jemand erklären, warum das ganze per while Schleife / ohne Thread.Sleep nicht zuverlässig funktioniert?

Vielen Dank!

M
35 Beiträge seit 2009
vor 14 Jahren

Ohne Gewähr:

Du hast es eigentlich schon ganz richtig gesagt.
In der while-Schleife wird sofort abgefragt ob Daten verfügbar sind.
In der do-while-Schleife wird der erste Durchgang schon durchgeführt, dann wird geschaut ob weitere Daten verfügbar sind.

Das ganze hat was mit Timing zu tun.
while-Schleife: Es kann ja gut sein, dass noch garkeine Daten verfügbar sind, zum Zeitpunkt der ersten Abfrage.
do-while-Schleife: Daher wird erstmal gewartet, bis der Stream die ersten Daten (Maximal soviele wie die Länge des Buffers) eingelesen hat. Damit wird sicher gestellt, dass es tatsächlich soweit ist, dass die Daten vom anderen Ende über den Stream angekommen sind.

Also sollte theoretisch auch folgendes klappen (Damit du deine while-Schleife benutzen kannst (;)

while (!stream.DataAvailable)
{
	Thread.Sleep(50);
}

while (stream.DataAvailable)
{
	//Daten einlesen...
}

Damit wäre auch die Frage beantwortet wieso es mit der auskommentierten Sleep()-Methode und beim Debuggen funktioniert.
Einfach weil beidesmal die Daten mehr Zeit haben anzukommen.

Lg Chris (;

S
srynoname Themenstarter:in
223 Beiträge seit 2006
vor 14 Jahren

danke für deine antwort!
also ich finde das mit dieser zeitverzögerung einfach komisch, wenn ich z.b. 2x hintereinander daten abrufen will:

  do
            {
                bytes = stream.Read(buffer, 0, buffer.Length);
            } while (stream.DataAvailable);
do
            {
                bytes = stream.Read(buffer, 0, buffer.Length);
            } while (stream.DataAvailable);

hängt sich das ganze programm auf, weil es beim 2. abfragen natürlich keine weiteren daten gibt. wenn ich also einmal nicht aufpasse, hängt sich mein ganzes programm auf. und wenn ich das ganze ohne thread.sleep mache, also do while

  do
            {
                bytes = stream.Read(buffer, 0, buffer.Length);
            } while (stream.DataAvailable);

wie in der msdn, wer garantiert mir, das hier eben schon immer daten vorhanden sind und mein programm sich nicht aufhängt, weil eben noch keine daten vorhanden sind? da muss es doch eine geschickte lösung geben? ?(

M
35 Beiträge seit 2009
vor 14 Jahren

Dann lager den Thread aus.
Und wenn alle Daten empfangen sind, soll er ein Event aufrufen.
Dann wird auch deine GUI oder whatever nicht blockiert.

Lg Chris

S
srynoname Themenstarter:in
223 Beiträge seit 2006
vor 14 Jahren

hmm das wäre eine möglichkeit, nur dass ich dann unnötig einen thread dauerhaft laufen habe. könnte sich jmd. dazu äußern, wie man das ganze wirklich richtig umsetzt? da muss es doch irgendetwas optimaleres geben ):

4.942 Beiträge seit 2008
vor 14 Jahren

Langanhaltende Methoden sollten immer in einem eigenen Thread ausgeführt werden (und bei Netzwerkzugriffen kannst du nie sicher sein, daß sie kurz genug ausgeführt werden (<10ms), um die GUI nicht zu blockieren).

Außerdem kannst du dann evtl. einfach den Thread innerhalb deines Programmes killen (und evtl. neu erzeugen), falls er mal nicht reagiert.

P
992 Beiträge seit 2007
vor 14 Jahren

Die Frage ist, woher weiß ich, wann alle Daten empfangen wurden?

2.760 Beiträge seit 2006
vor 14 Jahren

Das weisst nur du 😉 Es ist ja ein dir bekanntes Protokoll..
Ansonsten glaube ich meinst du eher die Kommunikation mit dem GUI-Teil deiner Anwendung?! Da kannst du einfach ein Received-event benutzen.

[EDIT]
Ansonsten kannst du sicher das hier auch auf Tcp übertragen: Simpler UDP-Server macht nach 1 Paket dicht... 😕

P
992 Beiträge seit 2007
vor 14 Jahren

Hallo jaensen,

in dem Beispiel wird aber ewig (bis _interrupt == true) empfangen. Ich weiß nicht, wann ich das letzt UDP-Packet empfangen habe, oder ob noch etwas kommt.

Ich möchte DataAvailable in meinem Http-Server verwenden. Auch dort habe ich das Problem, dass ich nicht weiß wann ich alles empfangen habe. Ich könnte/müsste halt die Content-Length auswerten.
Ich hatte halt erwartet, dass DataAvailable nur false wird, wenn man alles komplett empfangen hat.

2.760 Beiträge seit 2006
vor 14 Jahren

Wenn du auf so einem niedrigen Level arbeitest dann musst du nun mal selbst wissen wann schluss ist 😉 Es könnte ja beispielsweise auch sein das du kontinuierlich daten Empfangen möchtest zwecks Video/Audiostreaming oder etwas ähnlichem. Dem Socket bzw. TcpClient ist das aber herzlich wurscht.

Bei Http kannst du doch genau nach Spezifikation arbeiten und hast damit eigentlich alle Informationen die du brauchst. (HTTP 1.1 RFC) ansonsten kanns du sicherlich auch mal einen Blick in den Quelltext von pdelvo mit seinem Http-Server werfen: HTMLCP-Hypertext Markup Language C# Preprocessor