Laden...

EndRead(ar); liest nicht korrekt

Erstellt von KuGBeginner vor 2 Jahren Letzter Beitrag vor 2 Jahren 278 Views
K
KuGBeginner Themenstarter:in
21 Beiträge seit 2015
vor 2 Jahren
EndRead(ar); liest nicht korrekt

Hallo an das Forum,
ich bitte um Unterstützung bei folgender Fragestellung.

Ich möchte Daten von Programm1 an Programm2 übergeben, in Programm2 bearbeiten und diese Daten an Programm1 zurückgeben.
Es handelt sich um wenigstens 1000 historische Daten und realtime um 60 Daten pro Minute.
Es sollen ca. 15 Variablen (int, double, string und bool) in einer Reihe als string übergeben werden.
Hierzu verwende ich einen NamedPipeServer, der die Daten empfängt und grundsätzlich auch korrekt formatiert.
Mein Problem ist, dass „EndRead(ar)“ nicht immer das korrekte Ende der Reihe findet.
Ich verwende folgenden Code:


private async void ReadStream(IAsyncResult ar)
{
    ClientMessage cmo = (ClientMessage)ar.AsyncState; //Get the message object
    if (_currentServer == null) return;
    int recv = _currentServer.EndRead(ar);  //Receive data  FEHLER

    if (recv > 0)   //If data received
    {
       //Convert msg to string
       byte[] read = new byte[recv];
       Buffer.BlockCopy(cmo.buffer, 0, read, 0, recv);
       string message = Encoding.Unicode.GetString(read);
	 // ……
	
    }

Array.Clear(cmo.buffer, 0, cmo.buffer.Length);    //Free the byte array

if (_currentServer != null)				//Copy
_currentServer.BeginRead(cmo.buffer, 0, cmo.buffer.Length, new AsyncCallback(ReadStream), cmo);


Im Dateianhang wird von Zähler 1 bis 80 der string korrekt ausgegeben.
Von Zähler 81 bis 85 wird der string als ein Gesamtstring gelesen, weshalb die Reihenfolge der Daten nicht mehr korrekt ist und als Folgefehler ab diesem Bereich eine Zuweisung der Daten im korrekten Format nicht mehr möglich ist.

Meine Frage lautet deshalb: Wie kann man das fehlerhafte Lesen unterbinden?
Mein Arbeitsstand:
• Task.Delay(1).Wait(); in Programm 1 führt nicht immer zu korrekten Ergebnissen und verlangsamt den Prozess deutlich
• Die Übergabe von /r/n oder „EOF“ löst das Problem nicht (oder ich habe es nicht korrekt programmiert?)
• Die Synchronisation über identische Counter funktioniert nicht; es fehlen die Daten => 81-85 wird nicht gezählt
• .Contains(); .Split() usw. des Strings funktionieren nicht, weil die erforderlichen Daten fehlen

Vielen Dank für die Unterstützung!

PS: Eigentlich sollte es sich bei meinem Anliegen um ein Standardproblem handeln; kann jemand im Forum ein funktionierendes Codebeispiel empfehlen?

T
2.224 Beiträge seit 2008
vor 2 Jahren

Mir ist nicht klar wie du dort die Daten zwischen den Programmen hin und her schiebst.
Im einfachsten Fall kannst du die Daten z.B. als Parameter String (Argument) an das Programm übergeben.
Die Ausgabe des Programms kannst du dann als Rückgabe verwenden.

Oder soll das zweite Programm dauerhaft laufen als z.B. Worker Prozess?
Kann dein erstes Programm die Daten nicht selbst verarbeiten?
Dann kannst du dir den Umweg sparen.

Ansonsten würde ich schauen, dass du z.B. über einen Selfhosted WCF Service die Daten an das Programm schickst und dann auf die Antwort wartest.
Alternativ kannst du auch asynchron die Verarbeitung durchlaufen.

Anbei sagt der Titel deines Threads vermutlich kaum jemanden etwas.
Hier solltest du genauer erklären mit welchen Techniken du arbeitest und wo es klemmt.

Nachtrag:
Hab gerade in die Doku geschaut aber mir ist nicht ganz klar wie du dort mit NamedPipes arbeitest.
Laut der Doku gibt es hier NamedPipeServerStream und NamedPipedClientStream.
Dort kannst du eingetlich ganz einfach mit StreamReader/StreamWriter auch Zeilenbasiert arbeiten

Doku:
NamedPipeClientStream.Connect Method (System.IO.Pipes)
https://docs.microsoft.com/en-us/dotnet/api/system.io.pipes.namedpipeserverstream.waitforconnection?view=netframework-4.8

Hab zwar selbst noch nicht damit gearbeitet, dürfte dann aber die einfachste Lösung sein.

Nachtrag 2:
Anstelle des uralten IAsyncResult solltest du dir async/await anschauen.
Das alte Muster ist noch aus vor .NET 4.0 Zeiten bevor es Tasks gab.
Das sollte man heute nicht mehr verwenden bzw. nur noch wenn es nötig ist.
Aus heutiger Sicht ist das Muster veraltet und durch async/await einfacher gelöst.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

K
KuGBeginner Themenstarter:in
21 Beiträge seit 2015
vor 2 Jahren

Hallo T-Virus,
vielen Dank für Deine Rückmeldung!
Programm 1 schreibt über einen Client an Programm 2 Server und ich übergebe x-mal einen String mit den beschriebenen 15 Variablen.
Diese müssen im Server formatiert werden. Das funktioniert aber nicht, weil der Lesevorgang nicht immer das Ende des einzelnen Strings erkennt.
Der Datenaustausch soll so lange erfolgen, wie Programm 1 aktiv ist (mehrere Stunden).

Es verbleibt bei meiner Frage, wie ich die EndRead(ar)- Methode zum korrekten Lesen am Ende eines Strings bringen kann.
Vielen Dank für die Hilfe!

4.939 Beiträge seit 2008
vor 2 Jahren

Hallo,

du kannst nicht erwarten, daß immer nur zeilenweise gelesen wird (TCP/IP kennt gar keine Zeilen). Es scheint meistens zu funktionieren, weil wahrscheinlich das Schreiben eine gewisse Zeit dauert und in der Zwischenzeit dann der letzte Text gelesen wird (ebensowenig ist daher ein Delay immer erfolgreich).

Du benötigst ein Protokoll, mit dem du die Daten schreibst und verarbeitest (d.h. hierfür einen Parser). Im einfachsten Fall sollten Zeilenendekennzeichen dafür ausreichen, d.h. du liest blockweise, ermittelst dort dann das Zeilenende und extrahierst dann den vorherigen Text (solange bis kein Zeilenende mehr vorliegt). Den restlichen Text speicherst du und fügst dann den neuen gelesenen Puffertext hinzu und parst ihn dann wieder etc.