Laden...

[erledigt] Daten aus dem Networkstream lesen

Erstellt von Rioma vor 9 Jahren Letzter Beitrag vor 9 Jahren 4.538 Views
R
Rioma Themenstarter:in
228 Beiträge seit 2013
vor 9 Jahren
[erledigt] Daten aus dem Networkstream lesen

Hallo zusammen,

ich sitze jetzt schon das ganze Wochenende an einem Problem und ich komme einfach nicht darauf. Ich hoffe einer von euch kann mir helfen.

Ich lese Daten aus einem Networkstream und füge sie dann einer List<byte> hinzu, dass sieh so aus: (TcpClient)


 public void ReceiveData()
        {

            _serverStream = _clientSocket.GetStream();
            _serverStream.ReadTimeout = 100;

            byte[] bytes = new byte[128];
            List<byte> allBytes = new List<byte>();

            while (true)
            {
                if (_serverStream.DataAvailable)
                {
                    int i = 0;
                    do
                    {
                        try
                        {
                            i = _serverStream.Read(bytes, 0, bytes.Length);
                            allBytes.AddRange(bytes.Take(i));
                        }
                        catch (Exception e)
                        {
                            MessageBox.Show(e.Message + " " + i);
                        }
                    } while (i > 0);
                }
                else
                {
                    break;
                }
            }

            OnMessageRecieved(new MessageRecievedEventArgs(allBytes.ToArray()));
            allBytes.Clear();

        }

Leider komme ich nie aus der inneren Schleife raus und bekomme eine IOException geworfen (Von der Übertragungsverbindung usw....).
i wird aus irgendeinem Grund nie 0.

Nun das schreiben vom Server aus.


public static void GetDrives(TcpClient client)
        {
            NetworkStream networkStream = client.GetStream();

            byte[] bytesOption = Encoding.ASCII.GetBytes("A");
            networkStream.Write(bytesOption, 0, bytesOption.Length);


            DriveInfo[] allDrives = DriveInfo.GetDrives();

            foreach (DriveInfo d in allDrives)
            {
                if (d.IsReady)
                {
                    byte[] bytes = Encoding.ASCII.GetBytes(d.RootDirectory + " " + d.VolumeLabel + " " + d.DriveFormat + " " + d.TotalSize / 1024 / 1024 + " ~ ");
                    networkStream.Write(bytes, 0, bytes.Length);
                }
            }

            networkStream.Flush();
        }

ich schreibe hier zu Testzwecken einfach meine Laufwerke zurück.

Sieht jemand meinen Fehler? Lege ich den Try Catch Block außerhalb von der Schleife, sodass rausgesprungen wird bei einer Exception funktioniert alles und alle Daten finden ihren Weg.

Danke euch 😃

Edit:

  byte[] bytesOption = Encoding.ASCII.GetBytes("A");
   networkStream.Write(bytesOption, 0, bytesOption.Length);

Ich schreibe übrigens erst ein A in den Stream, damit der Client weiß wie er damit umgehen soll.
Quasi als Kommando.

16.830 Beiträge seit 2008
vor 9 Jahren

Die Begründung der IOException und die korrekte Implementierung des Lesens eines Network Streams findest Du im ersten Google Treffer bei der Suche nach "c# read from network stream" unter: What is the correct way to read from NetworkStream in .NET

if the ReceiveTimeout is reached an IOException will be raised...
with an InnerException of type SocketException and ErrorCode 10060

R
Rioma Themenstarter:in
228 Beiträge seit 2013
vor 9 Jahren

Ich habe natürlich gegoogelt bevor ich hier um helfe gebeten habe.

Ich habe _serverStream.ReadTimeout = 100; auch schon auf 10 Sekunden gesetzt, es macht leider keinen Unterscheid. Außerdem teste ich momentan nur auf meinem Rechner, wo die response nicht allzu hoch sein sollte.

Es funktioniert so zwar, aber es kann ja auch nicht sein, dass es so gedacht ist, immer eine Exception zu ignorieren oder?


     while (true)
            {
                if (_serverStream.DataAvailable)
                {
                    int i = 0;
                    
                        do
                        {
                            try
                            {
                                i = _serverStream.Read(bytes, 0, bytes.Length);
                                allBytes.AddRange(bytes.Take(i));
                            }
                            catch (IOException ex)
                            {
                                var socketExept = ex.InnerException as SocketException;
                                if (socketExept == null || socketExept.ErrorCode != 10060)
                                    // if it's not the "expected" exception, let's not hide the error
                                    throw ex;
                                // if it is the receive timeout, then reading ended
                                i = 0;
                            }

                        } while (i > 0); 
                }
                else
                {
                    break;
                }
            }
16.830 Beiträge seit 2008
vor 9 Jahren

Du ignorierst sie nicht; Du behandelst sie. Zwei völlig verschiedene Dinge.
Dass das Timeout hier funktional gewollt ist, ist ja nachvollziehbar: read liefert halt nichts, wenn nichts da ist und wirft dann nen Timeout.
Muss sogar so gemacht werden, wenn man statt einer while schleife eine do-while nimmt.

R
Rioma Themenstarter:in
228 Beiträge seit 2013
vor 9 Jahren

Danke für deine Hilfe.

"Muss sogar so gemacht werden, wenn man statt einer while schleife eine do-while nimmt. "

Ich kann dir leider nicht ganz folgen, ich habe das ganze auch schon so probiert:


 while ((i = _serverStream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        allBytes.AddRange(bytes.Take(i));
                    }

leider hatte ich dieselbe Exception und i wird nie 0. Normalerweise liefert die Funktion Read aber doch 0 zurück, sobald nichts mehr im Stream steht.

16.830 Beiträge seit 2008
vor 9 Jahren

Nicht unbedingt. Read gibt nur dann 0 zurück, wenn die Gegenseite den Stream geschlossen hat.
Da ein NetworkStream aber "kein Ende kennt", sondern einfach wartet, ob nicht noch irgendwas kommt MUSS auf den Timeout reagiert werden.

Aus diesem Grund hat der NetworkStream auch die DataAvailable-Eigenschaft.

R
Rioma Themenstarter:in
228 Beiträge seit 2013
vor 9 Jahren

Achso! Jetzt wird einiges klarer, Danke!