鉴于以下代码,修改自Stephen Toub的文章。 http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx
public async Task Start(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
await this.acceptCount.WaitAsync(token).ConfigureAwait(false);
if (token.IsCancellationRequested)
break;
var args = new SocketAsyncEventArgs();
args.UserToken = new SocketFrame
{
CancellationToken = token,
Buffer = null,
Message = null,
};
// How do I manage this additional task?
args.Completed += (s, e) => this.AcceptInbound((Socket)s, e).Wait(token);
if (!this.socket.AcceptAsync(args))
await this.AcceptInbound(this.socket, args);
}
}
private async Task AcceptInbound(Socket sender, SocketAsyncEventArgs e)
{
var frame = (SocketFrame)e.UserToken;
this.acceptCount.Release();
Socket connectedClient = e.AcceptSocket;
var args = new SocketAsyncEventArgs();
args.SetBuffer(new byte[0x1000], 0, 0x1000);
var awaitable = new SocketAwaitable(args);
while (!frame.CancellationToken.IsCancellationRequested)
{
await connectedClient.ReceiveAsync(awaitable);
var bytesRead = args.BytesTransferred;
if (bytesRead <= 0)
break;
if (this.AppendByteArrayToFrame(frame, args.Buffer, bytesRead))
this.reader.MessageReceived(frame.Message);
}
}
如何避免Wait
事件的args.Completed
?
我希望在AcceptInbound中引发的异常会冒出来,所以我真的不想在那里等待。
我想要实现的是将AcceptInbound任务绑定到当前任务,这样当我等待当前任务时,会捕获引发的异常。
答案 0 :(得分:1)
您可以注册一个async
事件处理程序(这是async void
唯一适合的地方)。这样您就可以await
而不是使用Wait
阻止
args.Completed += async (s, e) => await AcceptInbound((Socket)s, e);
如果您希望Start
处理所有这些任务的完成和异常,那么我会将它们全部存储起来,直到Start
完成,然后使用Task.WhenAll
确保所有操作都完成并重新抛出他们可能产生的任何例外:
public async Task Start(CancellationToken token)
{
var tasks = new ConcurrentBag<Task>();
while (!token.IsCancellationRequested)
{
// ...
args.Completed += (s, e) => tasks.Add(AcceptInbound((Socket)s, e));
// ...
}
await Task.WhenAll(tasks);
}
答案 1 :(得分:0)
看看这个:
private TaskCompletionSource<Something> _tcs = new TaskCompletionSource<Something>();
public void FinishAwait(Something result) {
_tcs.SetResult(result);
}
public void FailAwait(Exception exception) {
_tcs.SetException(exception);
}
public async Task<Something> M() {
var result = await _tcs.Task;
return result;
}
这是一种非常自定义的方式,用于控制特定Task
何时以及如何完成。
您可以使用await
自定义构建的任务,该任务由AcceptAsync
操作的事件处理程序完成手动触发。
在您的情况下,通用参数T
可以是object
,因为我们只需要它void
而object
是所有类型中最为良性的。
然后,您可以在等待Start
方法的AcceptInbound
之前等待Task
方法中的中间任务。
你的问题不是没有传递例外
通过等待呼叫来呼叫来电,而不是你
太快调用AcceptIncomming
。
在true
的调用中简单地接收AcceptAsync
并不意味着“已发生接受”,而是成功启动。
看一下代码的那一部分:
public async Task Start(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
await this.acceptCount.WaitAsync(token).ConfigureAwait(false);
if (token.IsCancellationRequested)
break;
var args = new SocketAsyncEventArgs();
args.UserToken = new SocketFrame
{
CancellationToken = token,
Buffer = null,
Message = null,
};
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
// How do I manage this additional task?
args.Completed += (s, e) => {
switch (e.SocketError) {
case SocketError.Success:
tcs.SetResult(null);
break;
default:
tcs.SetException(new SocketException());
break;
}
};
if (!this.socket.AcceptAsync(args)) {
// receiving a true value here
// only means that AcceptAsync
// started successfully
// we still need to
// "await for the Completed event handler"
await tcs.Task; // this will automatically throw
// if tcs.SetException(...) was used
// also, it will return null if all is well
// but most importantly, it will allow us to
// know when to call the next method
await this.AcceptInbound(this.socket, args);
}
}
}