TcpClient BeginConnect超时 [英] TcpClient BeginConnect timeout

查看:145
本文介绍了TcpClient BeginConnect超时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在c#中为BeginConnect异步调用设置自定义超时?在连接到主机时有可能不监听给定端口,这非常有用.每个这样的调用浪费大约15秒钟的时间来释放线程.

How can setting a custom timeout for BeginConnect async call be accomplished in c#? It is very useful, while connecting to a host with a chance of not listening on given port. Each such call wastes around 15s of time before releasing the Thread.

我有以下代码,正如许多stackoverflow答案中所建议的那样:

I have following code, as advised in many stackoverflow answers:

public bool Test()
{
     using (var tcp = new TcpClient())
     {
         var c = tcp.BeginConnect(IPAddress.Parse("8.8.8.8"), 8080, null, null);
         var success = c.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));

         if (!success)
         {
             Console.WriteLine("Before cleanup");
             tcp.Close();
             tcp.EndConnect(c);
             Console.WriteLine("After cleanup");
             throw new Exception("Failed to connect.");
         }
     }

     return true;
}

但是,这不起作用.实际上,在调用之后,该函数会进入"if"开关,但会在 tcp.Close()调用后立即阻塞,并等待上述15秒.可以避免吗?

However this does not work. Indeed after the call, the function enters the "if" switch but it blocks immediately on tcp.Close() call and waits for mentioned 15s. Can it be avoided somehow?

推荐答案

我编写了一个简单的测试程序,使用两种不同的技术来实现您的目标,并测试您发布的确切代码.我无法重现您正在描述的问题.无论我直接使用 TcpClient 还是 Socket ,在对象上调用 Close()都会导致连接操作立即完成(不到1个)在所有异步完成,异常处理,线程同步等之后的/10秒.

I wrote a simple test program, using two different techniques for accomplishing your goal, as well as also testing the exact code you posted. I was unable to reproduce the problem you are describing. Whether I use TcpClient or Socket directly, calling Close() on the object results in the connection operation completing immediately (well, in less than 1/10th of a second, after all the async completion, exception handling, thread synchronization, etc.)

请注意,在 TcpClient 情况下, TcpClient 类似乎存在一个错误,因为它引发了 NullReferenceException 而不是(会出现) ObjectDisposedException .这似乎是因为调用 Close()时, TcpClient Client 属性设置为 null ,然后尝试在调用完成委托时使用该值.糟糕!

Do note that in the TcpClient case, the TcpClient class seems to have a bug in that it throws NullReferenceException instead of (as one would expect) ObjectDisposedException. This appears to be because TcpClient sets the Client property to null when Close() is called, but then tries to use that value when invoking the completion delegate. Oops.

这意味着在您的代码中,调用者将看到 NullReferenceException 而不是您似乎要抛出的 Exception .但这似乎并不会导致实际的延迟.

That means that in your code, the caller would see NullReferenceException instead of the Exception you seem to want to throw. But that doesn't seem like it would cause an actual delay per se.

这是我的测试程序:

class Program
{
    static void Main(string[] args)
    {
        _TestWithSocket();
        _TestWithTcpClient();

        try
        {
            _TestSOCode();
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception: " + e);
        }
    }

    private static void _TestSOCode()
    {
        using (var tcp = new TcpClient())
        {
            var c = tcp.BeginConnect(IPAddress.Parse("8.8.8.8"), 8080, null, null);
            var success = c.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));

            if (!success)
            {
                Console.WriteLine("Before cleanup");
                tcp.Close();
                tcp.EndConnect(c);
                Console.WriteLine("After cleanup");
                throw new Exception("Failed to connect.");
            }
        }
    }

    private static void _TestWithTcpClient()
    {
        TcpClient client = new TcpClient();
        object o = new object();

        Console.WriteLine("connecting TcpClient...");
        client.BeginConnect("8.8.8.8", 8080, asyncResult =>
        {
            Console.WriteLine("connect completed");

            try
            {
                client.EndConnect(asyncResult);
                Console.WriteLine("client connected");
            }
            catch (NullReferenceException)
            {
                Console.WriteLine("client closed before connected: NullReferenceException");
            }
            catch (ObjectDisposedException)
            {
                Console.WriteLine("client closed before connected: ObjectDisposedException");
            }

            lock (o) Monitor.Pulse(o);
        }, null);

        Thread.Sleep(1000);

        Stopwatch sw = Stopwatch.StartNew();
        client.Close();

        lock (o) Monitor.Wait(o);
        Console.WriteLine("close took {0:0.00} seconds", sw.Elapsed.TotalSeconds);
        Console.WriteLine();
    }

    private static void _TestWithSocket()
    {
        Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
        object o = new object();

        Console.WriteLine("connecting Socket...");
        socket.BeginConnect("8.8.8.8", 8080, asyncResult =>
        {
            Console.WriteLine("connect completed");

            try
            {
                socket.EndConnect(asyncResult);
                Console.WriteLine("socket connected");
            }
            catch (ObjectDisposedException)
            {
                Console.WriteLine("socket closed before connected");
            }

            lock (o) Monitor.Pulse(o);
        }, null);

        Thread.Sleep(1000);

        Stopwatch sw = Stopwatch.StartNew();
        socket.Close();

        lock (o) Monitor.Wait(o);
        Console.WriteLine("close took {0:0.00} seconds", sw.Elapsed.TotalSeconds);
        Console.WriteLine();
    }
}

不幸的是,您没有提供实际的完整代码示例来演示该问题.如果上面的代码在您的环境中演示了您所描述的问题,那么,由于在我的环境中没有,那么显然这意味着您的环境中存在某些问题.不同的OS版本,不同的.NET版本等.

Unfortunately, you have not provided an actual complete code example demonstrating the problem. If in your environment the above code demonstrates the problem you describe then, since it doesn't do so in my environment, that obviously means there's something about your environment causing the problem. Different OS version, different .NET version, etc.

在这种情况下,您应该具体说明环境中可能相关的特定方面.

In that case, you should be specific about the particular aspect of your environment that might be relevant.

如果上面的代码示例按预期工作,并且没有演示您描述的问题,那么您只需要弄清楚代码中有什么不同并引起问题.在这种情况下,如果仍然无法真正解决问题,则应发布 a minimum 完整的代码示例来演示该问题.

If the above code example works as desired, and does not demonstrate the problem you describe, then you simply need to figure out what is in the code you have that is different and causing the problem. In that case, if you still can't actually figure out the problem, you should post a minimal, complete code example that demonstrates the problem.

这篇关于TcpClient BeginConnect超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆