2013-03-07 103 views
10

NetworkStream.ReadAsync()を使用してデータを読み取ろうとしていますが、一度呼び出されたReadAsync()をキャンセルする方法が見つかりません。バックグラウンドでは、NetworkStreamは、(32Feet.NET Bluetooth Libraryの)接続されたBluetoothClientオブジェクトによって私に提供されます。ストリームを閉じることなくNetworkStream.ReadAsyncをキャンセルする方法

私が試している現在のget-it-workingコードは以下のとおりです。

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"); 

コード微細受信データを動作し、continueReadingフラグがfalseに設定され、データが受信された場合、ループを停止しますが、データが受信されるまで、ReadAsync()ラインを越えて進行しないであろう。データを受信せずにコールを中止する方法はわかりません。

CancellationTokenを提供するReadAsyncのオーバーロードがありますが、NetworkStreamはデフォルトのReadAsync動作をオーバーライドしないため、トークンは無視されます(NetworkStream.ReadAsync with a cancellation token never cancels参照)。

基本ストリームを閉じようとしましたが、待機中のReadAsync呼び出しによってObjectDisposedExceptionがスローされ、基盤となるBluetooth接続も閉じられます。理想的には、読書を止めるためにデバイスとの接続を完全に切断したくないのです。これを行うのはきれいな方法ではなく、ストリーム全体を分解してReadAsync()呼び出しを中断する必要はありません。

アドバイスはありますか?

答えて

1

NetworkStream.Read(またはReadAsync)の周りに非同期ラッパーを実装することができます。これは、自分自身を監視して尊重するcancelationtokenも受け取ります。このような何か:

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); 
} 

私だけの考えを説明しようとしていますし、ループ、任意の追加の処理やクリーンアップしながら、あなたは} {Task<TResult>を返すことを検討するWNTかもしれない、と同様にDOを持っているかどうかということに注意してください、すべてあなたの必要に応じて。

Stephen Toub How do I cancel non-cancelable async operations?の記事とそこに作成したWithCancellation拡張機能にも注意してください。

+0

私はDataAvailableのチェックを忘れたいです!サンプルコードとStephen Toubの記事へのリンクをありがとう。どちらも私が後になったことを達成するのに役立ちます。ありがとう! – Swampie

8

内部コールが管理されておらず、IOCompletionポートを使用しているため、ReadAsyncをキャンセルすることはできません。オプションは次のとおりです。

  1. Socket.Shutdown()を使用してください。これは、ソケットエラーであるOperationAbortedでReadAsyncを返します。
  2. 読み取りがタイムアウトするのを待ちます。
  3. ソケットから読み取る前にデータが利用可能であることを確認してください。
+0

残念ながら私はソケットを使用していないので、私はSocket.Shutdownを使用できるとは思わない。私は32Feet.NETからBluetoothClientを作成し、BluetoothClient.Connect()を呼び出します。接続したら、BluetoothClient.GetStream()経由でストリームを取得します。タイムアウトに関しては、ストリームのタイムアウトは同期Read()にのみ適用され、ReadTimeoutプロパティとReadAsync()がタイムアウトしないことを確認することで確認されます。ソケットから利用可能なデータをチェックすることについてのビットは役に立ちますが、私は完全に忘れてしまったことがあります。ありがとう – Swampie

+0

私の読書は私に失敗しました。私の無関係な答えがまだ助けられたと聞いてうれしいです。 –

+0

TCPClientを使用する場合、TCPClient.Close()メソッドを使用して、ハングしているreadAsync()呼び出しで例外を発生させることができます。 –

2

私はタスクがこのような非同期呼び出しと待つの文の間にキャンセルトークンのコールを待つことによって取り消しを管理していますが:

try { 

.... 

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

.... 

} 
catch (OperationCanceledException e) 
{ 
    // handle cancellation 
} 
関連する問題