私はrxを使い慣れていて、ドットネットでリアクティブエクステンションを使っていくつかのネットワークコードに取り組んでいます。私の問題は、非同期関数で作成したtcpClientのオブザーバブルが、私が供給しているトークンを介して取り消しをトリガするときに期待通りに完了していないことです。私はこれを実行すると、ローカルホストに接続する場合非同期関数で作成されたobservableを取り消す
public static class ListenerExtensions
{
public static IObservable<TcpClient> ToListenerObservable(
this IPEndPoint endpoint,
int backlog)
{
return new TcpListener(endpoint).ToListenerObservable(backlog);
}
public static IObservable<TcpClient> ToListenerObservable(
this TcpListener listener,
int backlog)
{
return Observable.Create<TcpClient>(async (observer, token) =>
{
listener.Start(backlog);
try
{
while (!token.IsCancellationRequested)
observer.OnNext(await Task.Run(() => listener.AcceptTcpClientAsync(), token));
//This never prints and onCompleted is never called.
Console.WriteLine("Completing..");
observer.OnCompleted();
}
catch (System.Exception error)
{
observer.OnError(error);
}
finally
{
//This is never executed and my progam exits without closing the listener.
Console.WriteLine("Stopping listener...");
listener.Stop();
}
});
}
}
class Program
{
static void Main(string[] args)
{
var home = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 2323);
var cancellation = new CancellationTokenSource();
home.ToListenerObservable(10)
.Subscribe(
onNext: c => Console.WriteLine($"{c.Client.RemoteEndPoint} connected"),
onError: e => Console.WriteLine($"Error: {e.Message}"),
onCompleted:() => Console.WriteLine("Complete"), // Never happens
token: cancellation.Token);
Console.WriteLine("Any key to cancel");
Console.ReadKey();
cancellation.Cancel();
Thread.Sleep(1000);
}
}
:ここで私はとの問題を抱えているコードの簡易版である2323年は、私が接続されているtcpClientsのシーケンスを取得することがわかります。しかし、私がcancelationトークンのキャンセルをトリガーすると、プログラムはリスナーを閉じずに、期待どおりにonCompletedイベントを出さずに終了します。私は間違って何をしていますか?
このコードはキャンセルされるため、キャンセルすると 'OperationCancelledException'がスローされます。 –
https://stackoverflow.com/questions/14524209/what-is-the-correct-way-to-cancel-an-async-operation-that-doesnt-accept-a-cance –
そして、これを見ると[Stephen Clearyの投稿](http://blog.stephencleary.com/2015/03/a-tour-of-task-part-9-delegate-tasks.html「タスクツアー、第9回:タスクの委任」 )、あなたは 'Task.Run'にキャンセルトークンを渡すことは、あなたが思うかもしれないものとまったく同じではないことがわかります。 –