我想用 TPL 包装以下数据报套接字操作以清理 API,以便它可以很好地与async
和一起使用await
,就像StreamSocket
类一样。
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;
}
症结在于MessageReceived
将DatagramSocket
类变成事件异步模式和新async
模式的奇怪混杂的事件。无论如何,TaskCompletionSource<T>
允许我调整处理程序以符合后者,所以这并不太可怕。
除非端点从不返回任何数据,否则这似乎工作得很好。与处理程序关联的任务MessageReceived
永远不会完成,因此返回的任务TestAsync
永远不会完成。
很好地包装此操作以合并超时和取消的正确方法是什么?我想扩展这个函数来CancellationToken
为后者提供一个参数,但是我该怎么做呢?我想出的唯一一件事是创建一个额外的“监控”任务Task.Delay
,我使用它传递一个超时值和取消令牌以支持这两种行为,如下所示:
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;
}
然而,这有各种各样的问题,包括延迟任务和MessageReceived
处理程序之间的潜在竞争条件。我从来没有能够让这种方法可靠地工作,而且它看起来非常复杂,而且线程池的使用效率低下。这很繁琐,容易出错,而且让我头疼。
旁注:我是唯一对DatagramSocket
API 感到困惑的人吗?它不仅看起来是IAsyncAction
WinRT 模型和 TPL 与一些棘手的 EAP 的丑陋组合,而且我对旨在表示基本无连接协议(例如包含ConnectAsync
在其中命名的方法的 UDP)的 API 不太满意。这对我来说似乎是一个矛盾。