【发布时间】:2014-07-19 18:10:14
【问题描述】:
我正在通过 TCP/IP 实现客户端协议 MyProtocol。协议的 Connect() 方法应该有一个类似于 TcpClient.ConnectAsync() 的签名——也就是说,它应该返回一个 Task:
Task MyProtocol.Connect (…);
这个方法(MyProtocol.Connect())应该建立异步 TCP/IP 连接(通过TcpClient.ConnectAsync()),返回一个未完成的任务 T,然后定期向服务器发送某个消息 M——再次异步(通过NetworkStream.WriteAsync() )。当从服务器接收到某个响应 R 时——再次异步(通过NetworkStream.ReadAsync()),MyProtocol.Connect() 应该完成任务 T。
我正在执行以下操作:
// Client of the protocol:
var task = myProtocol.Connect(); // asynchronous call, we don’t want to wait until connected
task.ContinueWith(t =>
{
// Connected – doing an OnConnected stuff
…
});
// MyProtocol.Connect() implementation:
public class MyProtocol
{
private Task connectTask;
public Task Connect(…)
{
var tcpIpConnectTask = mTcpIpProtocol.Connect(…);
tcpIpConnectTask.ContinueWith(t =>
{
connectTask = new Task();
}
return connectTask;
}
}
显然,必须通过计时器定期向服务器发送消息 M。一旦从服务器异步接收到响应 R,connectTask 必须标记为已完成,我看不到这样做的方法。
好吧,严格来说,我已经成功地将connectTask 标记为已完成;我将它包装在TaskCompletionSource<bool> 中并使用TaskCompletionSource.SetResult(true)。
但是我想知道这是否是唯一的,更不用说完成我需要的最佳方式了?我特别不喜欢 TaskCompletionSource<> 必须有一个非空任务结果类型(我使用 bool),即没有非泛型版本。
在 TPL 到来之前,我们有自己的类似框架和方法Task.NotifyCompleted(),因此我们可以在一个地方创建一个任务,并在另一个地方将其标记为已完成——所有这些都是异步工作的。但我所读到的关于 TPL 中任务的所有内容似乎都暗示一个任务只有在其委托运行到最后一行时才能完成……
还是我错过了一些简单的东西?
【问题讨论】:
-
你为什么不直接返回
tcpIpConnectTask?一旦连接完成,那一个就完成了。此外,如果您使用的是 .net 4.5,您可以使用async/await,这可以简化使用 -
tcpIpConnectTask本质上是TcpClient.ConnectAsync()返回的内容。如上所述,MyProtocol 为 TCP/IP 添加了自己的功能,所以它只能使用tcpIpConnectTask作为中间结果,它不能将它返回给客户端,因为tcpIpConnectTask时连接不会完成就 MyProtocol 而言,是完整的。
标签: c# asynchronous task-parallel-library task