Probleme mit dem Networkstream und asynchronem Lesen
-
Hallo c-plussplus Community,
ich bin gerade dabei einen TcpClient zu programmieren.
Die Verbindung mit einem Server und das synchrone lesen/schreiben funktioniert auch schon...
Nun möchte ich das lesen vom Networkstream über einen asynchronen Lesevorgang mittels BeginRead() realisieren.Aus der MSDN-Lib hab ich ein Beispiel gefunden, dass ich wie folgt angepasst habe:
Die BeginRead-Methode:
int TClient::DoBeginRead() { // Check to see if this NetworkStream is readable. if ( stream->CanRead ) { array<Byte>^myReadBuffer = gcnew array<Byte>(1024); stream->BeginRead( myReadBuffer, 0, myReadBuffer->Length, gcnew AsyncCallback( &TClient::myReadCallBack ), stream); allDone->WaitOne(); return 1; } else { } }
Das funktioniert auch soweit, dass die Methode gestartet wird wenn vom Server was kommt.... stream->DataAvailable ist auf true
Probleme gibt es allerdings dann in der ReadCallback, diese wird zwar aufgerufen, läuft durch... aber es passiert nix.
Wenn ich meinen Stream im Debugger beobachte ist stream->DataAvailable auf false, ich vermute, dass deswegen nix kommtvoid TClient::myReadCallBack( IAsyncResult^ arg ) { IAsyncResult^ ar_read = arg; // save ar_read flag for asynchrone read stream = safe_cast<NetworkStream^>(ar_read->AsyncState); array<Byte>^myReadBuffer = gcnew array<Byte>(1024); String^ myCompleteMessage = ""; int numberOfBytesRead; numberOfBytesRead = stream->EndRead( ar_read ); myCompleteMessage = String::Concat( myCompleteMessage, Encoding::ASCII->GetString( myReadBuffer, 0, numberOfBytesRead ) ); // message received may be larger than buffer size so loop through until you have it all. while ( stream->DataAvailable ) { AsyncCallback^ pasync = gcnew AsyncCallback( &myReadCallBack ); stream->BeginRead( myReadBuffer, 0, myReadBuffer->Length, pasync, stream ); } }
Im Moment bin ich noch in der Phase des ausprobieren mit den ganzen Asynchronen Vorgängen, daher komm ich auch nicht selbst dahinter wo der Fehler liegen könnte.
Hat jemand eine Idee? Ich wäre für jede Hilfe dankbar
mfg Tobi
-
Hi,
Wenn ich es richtig verstehe, dann benötigst Du beim asynchronen Empfang nicht auf das DataAvailable Flag zu achten. Ich denke es ist sogar so, dass wenn Du EndRead aufgerufen hast, eben genau DataAvailable false ist.Wie auch immer, da Du ja asynchron Empfängst, kannst Du im Callback einfach wieder BeginRead aufrufen.
DataAvailable ist, denke ich, für ein Polling Mechanismus geeigent, der synchron Empfängt.
http://msdn2.microsoft.com/en-us/library/system.net.sockets.networkstream.dataavailable.aspx
Gruss Simon
-
hmm... klingt ganz logisch.
Allerdings ist der Code aus http://msdn2.microsoft.com/en-us/library/system.net.sockets.networkstream.endread(VS.80).aspx
Dort wird mit
// message received may be larger than buffer size so loop through until you have it all. while ( myNetworkStream->DataAvailable ) { AsyncCallback^ pasync = gcnew AsyncCallback( &myReadCallBack ); myNetworkStream->BeginRead( myReadBuffer, 0, myReadBuffer->Length, pasync, myNetworkStream ); }
gebrüft ob noch mehr Daten im stream vorhanden sind. Bei mir ist das DataAvailable schon beim Methodenaufruf false, so dass nie irgendwelche Daten in meinen "myReadBuffer" kommen
-
Ich denke, wenn Du immer wieder Empfangen möchtest ist es nicht nötig DataAvailable miteinzubeziehen.
Ev. wird DataAvailable auf true belassen, wenn Du einen kleineren Buffer übergibts, als das Bytes im Stream stecken. So gesehen, würde das MS Bsp. Sinn machen, indem es sicher alle Daten aus dem Stream liesst. Dann liest es allerdings nicht mehr weiter.
Simon
-
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=120301&SiteID=1
Könnte noch interessant sein.
-
Ohje... so ist es halt immer, kaum frägt man nach... findet man den Fehler selbst.
In meinem Buffer ist nie was angekommen, weil ich in beiden Methoden verschiedene Buffer verwendet habearray<Byte>^myReadBuffer = gcnew array<Byte>(1024);
Ich habe den ReadBuffer nun direkt in die Klasse TClient gepackt, so dass er überall bekannt ist. Die Nachricht kommt nun auch an.
Jetzt muss ich nur noch hinter die ganze Eventgeschichte steigen und dann sollte es eigentlich funktionieren.
Ich komm bestimmt nochmal aufs Forum zurück
gruß