14

NetworkStream.ReadAsync() を使用してデータを読み取ろうとしていますが、一度呼び出された ReadAsync() をキャンセルする方法が見つかりません。背景として、NetworkStream は、接続された BluetoothClient オブジェクト (32Feet.NET Bluetooth ライブラリから) によって提供されます。

私が試している現在の作業コードは以下のとおりです。

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 を参照してください)。

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

何かアドバイス?

4

3 に答える 3

9

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

  1. Socket.Shutdown() を使用します。これにより、OperationAborted のソケット エラーで ReadAsync が返されます。
  2. 読み取りがタイムアウトするまで待ちます。
  3. ソケットから読み取る前に、データが使用可能かどうかを確認してください。
于 2013-03-07T21:34:18.383 に答える
4

NetworkStream.Read (または ReadAsync) の周りに非同期ラッパーを実装できます。これは、自分で監視して尊重できるキャンセルトークンも受け取ります。このようなもの:

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

私はアイデアを説明しようとしているだけであり、do while ループを使用するかどうか、追加の処理やクリーンアップなどを行うかどうかだけでなく、必要に応じて を返すことを検討しないかもしれないことに注意してくださいTask<TResult>。{}

また、Stephen Toub の記事に注意してください。キャンセルできない非同期操作をキャンセルするにはどうすればよいですか? そして彼がそこに作成する WithCancellation 拡張機能。

于 2013-03-07T16:35:55.933 に答える
2

次のように、async 呼び出しと await ステートメントの間のキャンセル トークン呼び出しを Task に待機させることで、キャンセルを管理しています。

try {

 ....

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

....

}
catch ( OperationCanceledException e )
{
   // handle cancellation
}
于 2016-08-11T10:30:40.720 に答える