异步TCP客户端连接挂起
本文关键字:挂起 连接 客户端 TCP 异步 | 更新日期: 2023-09-27 18:04:03
我正在使用异步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函数时,它立即正确返回"连接正在进行中…",然后显示一个异常,因为远程端点已关闭。太好了!
问题是它需要几秒钟来返回异常,我想给用户机会取消正在进行的操作。根据MSDN关于BeginConnect方法的规范,如果您希望中止异步操作,只需在工作套接字上调用Close。
因此,我尝试在末尾添加几行(如上所述注释掉),以模拟用户在2秒后取消。结果看起来像是应用程序的一个悬挂(沙漏)。通过暂停IDE,它停在最后一行t.Result.Client.Close()
上。但是,通过停止IDE,一切正常关闭,没有任何异常。
我也试过直接关闭客户端作为t.Result.Close()
,但它是完全相同的。
是我,还是连接过程中出了什么问题?
t.Result.Close()
将等待t
任务完成。t.ContinueWith()
也将等待任务完成。
要取消你必须等待两个任务:tcp和一个定时器。
使用异步tcp语法:
await Task.WhenAny(t,Task.Delay(QueryTimeout));
if (!t.IsCompleted)
tcpClient.Close(); //Cancel task
尝试在对象上调用Dispose()
-它比Close()
更具侵略性。您可以查看TcpClient
类上的各种Timeout成员,并将它们设置为更合适的值(例如,在局域网环境中1秒可能就足够了)。你也可以看看。net 4.0中的CancellationTokenSource
功能。这允许您向Task
发出信号,表示您希望它停止-我找到了一篇文章,可能会让您开始。
你还应该找出哪个线程实际上正在停止(主线程可能只是在等待另一个线程停止),例如.ContinueWith(_ => _.Result.Close())
可能是问题所在(你应该检查关闭套接字两次时的行为)。在调试时,打开线程窗口(调试-> Windows ->线程),查看每个线程。