C#等待TcpClient ConnectAsync / ReadToEndAsync超时

时间:2015-12-08 21:38:43

标签: c# asynchronous tcpclient

我正在使用.NET 4.5构建SOCKS代理检查程序,一切正常,除非其中一个SOCKS代理非常慢并且需要超过100秒才能响应。我想在几个阶段(ConnectAsync,ReadToEndAsync)超时这些代理,特别是在ReadToEndAsync,因为如果代理很慢,它会挂起。

我已经尝试了一切我能找到的,使用取消令牌,Task.Wait,NetworkStream.ReadTimeout(不起作用..奇怪).. 如果我使用Task.Wait然后我不能使用await关键字,这使得它同步而不是异步,并且击败了我的工具的整个想法..

 var socksClient = new Socks5ProxyClient(IP,Port);
                var googleAddress = await Dns.GetHostAddressesAsync("google.com");
                var speedStopwatch = Stopwatch.StartNew();
                using(var socksTcpClient = await socksClient.CreateConnection(googleAddress[0].ToString(),80))
                {

                    if(socksTcpClient.Connected)
                    {
                        using(var socksTcpStream = socksTcpClient.GetStream())
                        {
                            socksTcpStream.ReadTimeout = 5000;
                            socksTcpStream.WriteTimeout = 5000; //these don't work..
                            using (var writer = new StreamWriter(socksTcpStream))
                            {

                                await writer.WriteAsync("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n");
                                await writer.FlushAsync();
                                using (var reader = new StreamReader(socksTcpStream))
                                {
                                    var result = await reader.ReadToEndAsync(); // up to 250 seconds hang on thread that is checking current proxy..



                                    reader.Close();
                                    writer.Close();
                                    socksTcpStream.Close();
                                }
                            }
                        }
                    }
                }

1 个答案:

答案 0 :(得分:2)

可耻的是,异步套接字IO不支持超时。你需要自己构建它。这是我所知道的最佳方法:

让你的整个功能不关心超时。禁用所有这些。然后,启动延迟任务,并在完成插槽的处理时。这会杀死所有正在飞行的IO并立即取消。

所以你可以这样做:

Task.Delay(TimeSpan.FromSeconds(100)).ContinueWith(_ => socksTcpClient.Dispose());

这会导致丑陋的ObjectDisposedException。这是不可避免的。

可能需要在成功的情况下取消延迟。否则你会在100秒内完成大量延迟任务,根据负载情况,这些任务可能达到数百万。