【问题标题】:Hang-up on async TCP client connection挂断异步 TCP 客户端连接
【发布时间】:2011-08-01 11:02:32
【问题描述】:

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

是我,还是连接过程有什么问题?

非常感谢。

【问题讨论】:

    标签: c# sockets asynchronous connection task


    【解决方案1】:

    t.Result.Close() 将等待t 任务完成。 t.ContinueWith() 也会等待任务完成。

    要取消,您必须等待 2 个任务:tcp 和计时器。
    使用异步 tcp 语法:

    await Task.WhenAny(t,Task.Delay(QueryTimeout));
    if (!t.IsCompleted)
        tcpClient.Close(); //Cancel task
    

    【讨论】:

      【解决方案2】:

      尝试在对象上调用Dispose() - 它比Close() 更具侵略性。您可以查看TcpClient 类上的各种 Timeout 成员并将它们设置为更合适的值(例如,在 LAN 环境中 1 秒可能就足够了)。您还可以查看 .Net 4.0 中的 CancellationTokenSource 功能。这使您可以向Task 发出信号,表示您希望它停止 - 我找到了一个可能让您开始使用的article

      您还应该找出哪个线程实际上正在停止(主线程可能只是在等待另一个停止的线程),例如.ContinueWith(_ =&gt; _.Result.Close()) 可能是问题所在(您应该检查两次关闭套接字时的行为)。调试时打开线程窗口(调试 -> Windows -> 线程)并查看每个线程。

      【讨论】:

        猜你喜欢
        • 2016-05-24
        • 2014-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多