挂起异步TCP客户端连接

时间:2011-08-01 11:02:32

标签: c# sockets asynchronous connection task

我正在使用异步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(),但它完全一样。

这是我,还是连接过程中出现了什么问题?

提前多多感谢。

2 个答案:

答案 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)并查看每个线程。

相关问题