StreamSocket
のように、async
とawait
でうまく動作するように、APIをクリーンアップするためにTPLで以下のデータグラムソケット操作をラップしたいと思います。async/awaitで使用するためにDatagramSocket.MessageReceivedをどのように適合させますか?
public static async Task<bool> TestAsync(HostName hostName, string serviceName, byte[] data)
{
var tcs = new TaskCompletionSource<bool>();
var socket = new DatagramSocket();
socket.MessageReceived += (sender, e) =>
{
var status = false; // Status value somehow derived from e etc.
tcs.SetResult(status);
};
await socket.ConnectAsync(hostName, serviceName);
var stream = await socket.GetOutputStreamAsync();
var writer = new DataWriter(stream);
writer.WriteBytes(data);
await writer.StoreAsync();
return tcs.Task;
}
付着点はイベントの非同期パターンの奇妙寄せ集めと新しいasync
パターンにDatagramSocket
クラスをオンMessageReceived
イベントです。とにかく、TaskCompletionSource<T>
は私が後者に従うようにハンドラを適応させることができるので、あまり恐ろしいことではありません。
エンドポイントが決してデータを返さない限り、これはかなりうまくいくようです。 MessageReceived
ハンドラに関連付けられたタスクは完了しないため、TestAsync
から返されたタスクは完了しません。
この操作をうまくラップしてタイムアウトとキャンセルを組み込む正しい方法は何ですか?この関数を拡張して、後者の引数をCancellationToken
としたいのですが、どうすればいいですか?しかし、
public static async Task<bool> CancellableTimeoutableTestAsync(HostName hostName, string serviceName, byte[] data, CancellationToken userToken, int timeout)
{
var tcs = new TaskCompletionSource<bool>();
var socket = new DatagramSocket();
socket.MessageReceived += (sender, e) =>
{
var status = false; // Status value somehow derived from e etc.
tcs.SetResult(status);
};
await socket.ConnectAsync(hostName, serviceName);
var stream = await socket.GetOutputStreamAsync();
var writer = new DataWriter(stream);
writer.WriteBytes(data);
await writer.StoreAsync();
var delayTask = Task.Delay(timeout, userToken);
var t1 = delayTask.ContinueWith(t => { /* Do something to tcs to indicate timeout */ }, TaskContinuationOptions.OnlyOnRanToCompletion);
var t2 = delayTask.ContinueWith(t => { tcs.SetCanceled(); }, TaskContinuationOptions.OnlyOnCanceled);
return tcs.Task;
}
:私が作ってみただけの事は、私は次の行に沿って、これらの2つの動作をサポートするためのタイムアウト値とキャンセルトークンを渡すためにTask.Delay
を使用して「監視」の追加タスクを作成することですこれには、遅延タスクとMessageReceived
ハンドラの間の潜在的な競合状態を含むあらゆる種類の問題があります。私はこのアプローチを確実に動作させることはできませんでしたが、スレッドプールの非効率的な使用だけでなく、非常に複雑に思えます。間違っていて誤りがちで頭が痛い。
サイドノート:私は、一般的にDatagramSocket
APIで混乱している人だけですか?だけでなく、それは投入されたいくつかのトリッキーなEAPとIAsyncAction
WinRTのモデルとTPLの醜い寄せ集めのように見えるん、私はそのようなUDPがでConnectAsync
という名前のメソッドを含むように基本的にコネクションレスのプロトコルを表すことが意図されているAPIとひどく慣れていませんよそれら。これは私にとっては矛盾しているようです。
2番目のメソッド全体の代わりに、最初のタスクをTask.Delayと組み合わせてTask.WhenAnyを使用する新しいメソッドを作成します。あなたがあなたの仕事を完了するか、タイムアウトが発生した場合は、それを返します。 –