2013-03-07 11 views
10

Ich versuche, NetworkStream.ReadAsync() zu verwenden, um Daten zu lesen, aber ich kann nicht finden, wie die einmal aufgerufene ReadAsync() abgebrochen wird. Als Hintergrund wird mir der NetworkStream von einem verbundenen BluetoothClient-Objekt (von 32Feet.NET Bluetooth Library) zur Verfügung gestellt.Wie NetworkStream.ReadAsync Abbrechen ohne Stream zu schließen

Der aktuelle Get-it-working-Code, den ich versuche, ist unten.

int bytesRead; 

while (this.continueReading) 
{ 
    bytesRead = await this.stream.ReadAsync(this.buffer, 0, (int)this.buffer.Length); 

    Console.WriteLine("Received {0} bytes", bytesRead); 
} 

Console.WriteLine("Receive loop has ended"); 

Der Code funktioniert Empfangsdaten und Looping stoppt, wenn die continueReading Flag auf false gesetzt ist und Daten empfangen werden, aber bis Daten empfangen werden, wird es vorbei an der ReadAsync() Linie nicht fortgesetzt werden. Ich kann nicht sehen, wie ich den Anruf abbringe, ohne Daten zu empfangen.

Ich bin mir bewusst, dass es eine Überlastung der ReadAsync, die eine CancellationToken bietet, aber es scheint, dass als Network den Standard ReadAsync Verhalten nicht außer Kraft setzt, wird der Token ignoriert (siehe NetworkStream.ReadAsync with a cancellation token never cancels).

Ich habe versucht, den zugrunde liegenden Stream zu schließen, und dies führt dazu, dass der wartende ReadAsync-Aufruf ObjectDisposedException auslöst und die darunterliegende Bluetooth-Verbindung ebenfalls geschlossen wird. Idealerweise möchte ich die Verbindung mit dem Gerät nicht vollständig trennen, nur um das Lesen zu stoppen. Es scheint keine saubere Methode zu sein, es zu tun, und es ist unnötig, den gesamten Stream abzureißen, nur um den Aufruf von va ReadAsync() zu unterbrechen.

Irgendwelche Ratschläge?

Antwort

1

Sie können einen asynchronen Wrapper um NetworkStream.Read (oder ReadAsync) implementieren, der auch ein cancellationToken erhält, das Sie überwachen und ehren können. Etwas wie folgt aus:

Task MyCancelableNetworkStreamReadAsync(NetworkStream stream, CancellationToken ct) 
{ 
... 
if(this.stream.CanRead) 
{ 
    do 
    { 
    //check ct.IsCancellationRequested and act as needed 
    bytesRead = await this.stream.ReadAsync(this.buffer, 0, (int)this.buffer.Length); 
    } 
    while(myNetworkStream.DataAvailable); 
} 

Bitte beachten Sie, dass ich nur versuchen, die Idee zu veranschaulichen und man könnte Task<TResult> Rückkehr, aber auch zu berücksichtigen wnt als ob die tun haben {} while-Schleife, jede weitere Verarbeitung oder Bereinigung, usw. - alles nach Ihren Bedürfnissen.

Ich würde auch Ihre Aufmerksamkeit auf den Artikel von Stephen Toub How do I cancel non-cancelable async operations? und die WithCancellation Erweiterung, die er dort erstellt.

+0

ich Überprüfung DataAvailable vergessen hatte! Danke für den Beispielcode und den Link zu Stephen Toubs Artikel. Beide sind hilfreich für mich zu erreichen, dass ich danach bin. Vielen Dank! – Swampie

8

Sie können den ReadAsync-Vorgang nicht abbrechen, da der interne Aufruf nicht verwaltet wird und IOCompletion-Ports verwendet. Ihre Optionen lauten wie folgt.

  1. Verwenden Sie Socket.Shutdown(). Dies wird ReadAsync mit einem Socket-Fehler von OperationAborted zurückgeben.
  2. Warten Sie, bis der Lesevorgang beendet ist.
  3. Prüfen, ob Daten verfügbar sind, bevor sie aus dem Socket gelesen werden.
+0

Leider verwende ich keine Sockets, also glaube ich nicht, dass ich Socket.Shutdown verwenden kann. Ich erstelle einen BluetoothClient (von 32Feet.NET) und rufe BluetoothClient.Connect() auf. Sobald verbunden, erhalte ich den Strom über BluetoothClient.GetStream(). Wie bei der Zeitüberschreitung gibt die MSDN an, dass die Zeitüberschreitung des Streams nur für synchrones Read() gilt - bestätigt durch das Setzen der ReadTimeout-Eigenschaft und des ReadAsync() -Zeitlimits.Das bisschen über die Suche nach Daten aus dem Sockel ist hilfreich, und etwas, das ich völlig vergessen hatte. Danke – Swampie

+0

Mein Leseverständnis versagte mir. Ich bin froh zu hören, dass meine unzusammenhängende Antwort immer noch geholfen hat. –

+0

Bei Verwendung von TCPClient kann die Methode TCPClient.Close() verwendet werden, um eine Ausnahme bei einem hängenden Aufruf von readAsync() auszulösen. –

2

ich die Kündigung leite durch die Aufgabe für die Annullierung Token Anruf zwischen dem Asynchron-Aufruf und die erwarten Anweisung wie folgt warten:

try { 

.... 

Task<int> readTask = input.ReadAsync(buffer, 0, buffer.Length); 
readTask.Wait(myCancellationToken); 
int readBytes= await readTask; 

.... 

} 
catch (OperationCanceledException e) 
{ 
    // handle cancellation 
}