我正在使用异步CTP框架练习,作为练习,我将创建一个能够查询服务器的TCP客户端(使用任意协议)。无论如何,我在很早的阶段就陷入困境,因为连接上存在问题。要么我仍然不明白某些基本观点,要么有些奇怪。
所以,这是异步连接器:
public class TaskClient
{
public static Task<TcpClient> Connect(IPEndPoint endPoint)
{
//create a tcp client
var client = new TcpClient(AddressFamily.InterNetwork);
//define a function to return the client
Func<IAsyncResult, TcpClient> em = iar =>
{
var c = (TcpClient)iar.AsyncState;
c.EndConnect(iar);
return c;
};
//create a task to connect the end-point async
var t = Task<TcpClient>.Factory.FromAsync(
client.BeginConnect,
em,
endPoint.Address.ToString(),
endPoint.Port,
client);
return t;
}
}
我的意思是只调用此函数一次,然后返回一个TcpClient
实例用于任何后续查询(此处未显示的代码)。
在我的表格中,我按以下方式调用上述函数:
//this method runs on the UI thread, so can't block
private void TryConnect()
{
//create the end-point
var ep = new IPEndPoint(
IPAddress.Parse("192.168.14.112"), //this is not reachable: correct!
1601);
var t = TaskClient
.Connect(ep)
.ContinueWith<TcpClient>(_ =>
{
//tell me what's up
if (_.IsFaulted)
Console.WriteLine(_.Exception);
else
Console.WriteLine(_.Result.Connected);
return _.Result;
})
.ContinueWith(_ => _.Result.Close());
Console.WriteLine("connection in progress...");
//wait for 2" then abort the connection
//Thread.Sleep(2000);
//t.Result.Client.Close();
}
测试是尝试连接远程服务器,但必须无法访问(PC打开,但服务已停止)。
当我运行TryConnect函数时,它会立即正确返回“正在连接...”,然后显示异常,因为远程端点已关闭。优良!
问题是它需要几秒钟才能返回异常,我想让用户有机会取消正在进行的操作。根据有关BeginConnect方法的MSDN规范,如果您希望中止异步操作,只需在工作套接字上调用Close。
所以,我尝试在最后添加几行(如上所述),以便在2秒后模拟用户取消。结果看起来像应用程序的悬挂(沙漏)。通过暂停IDE,它会在最后一行t.Result.Client.Close()
停止。但是,通过停止IDE,一切都会正常关闭,没有任何例外。
我也试图直接关闭客户端t.Result.Close()
,但它完全一样。
这是我,还是连接过程中出现了什么问题?
提前多多感谢。
答案 0 :(得分:2)
t.Result.Close()
将等待t
任务完成。
t.ContinueWith()
也将等待完成任务。
要取消,您必须等待2个任务:tcp和计时器 使用async tcp语法:
await Task.WhenAny(t,Task.Delay(QueryTimeout));
if (!t.IsCompleted)
tcpClient.Close(); //Cancel task
答案 1 :(得分:1)
尝试在对象上调用Dispose()
- 它比Close()
更具攻击性。您可以查看TcpClient
类上的各种Timeout成员,并将它们设置为更合适的值(例如,LAN环境中的1秒可能足够好)。您还可以查看.Net 4.0中的CancellationTokenSource
功能。这样您就可以向Task
发信号通知您希望它停止发送 - 我发现article可能会让您开始使用。
您还应该找出哪个线程实际上正在停止(主线程可能只是在等待另一个停止的线程),例如: .ContinueWith(_ => _.Result.Close())
可能是问题(您应该检查关闭套接字两次时的行为)。在调试时打开Threads窗口(Debug - &gt; Windows - &gt; Threads)并查看每个线程。