2015-01-26 106 views
1

如何在C#中設置BeginConnect異步調用的自定義超時值? 這是非常有用的,當連接到一個主機有機會不聽特定端口。在釋放線程之前,每個這樣的呼叫都會在大約15秒的時間內浪費。TcpClient BeginConnect超時

我有下面的代碼,如建議在許多計算器答案:

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()呼叫並等待提到的15s。可以以某種方式避免嗎?

+0

可能重複的[如何設置TcpClient的超時?](http://stackoverflow.com/questions/17118632/how-to-set-the-timeout-for-a-tcpclient)另外,什麼是與手動處理*和*使用說明? – bzlm 2015-01-26 21:29:04

+0

感謝您的評論,但是「使用」是否存在並不重要。您的鏈接解決方案不起作用,並存在於我的代碼中。這是類似的問題,因爲在這裏:http://stackoverflow.com/questions/27417990/app-hangs-for-20-secs-on-exit-after-tcpclient-beginconnect – Josh 2015-01-26 21:31:19

+0

你找到解決辦法? – shahroz 2016-05-09 07:22:39

回答

0

我寫了一個簡單的測試程序,使用兩種不同的技術來完成您的目標,以及測試您發佈的確切代碼。我無法重現您所描述的問題。無論我是直接使用TcpClient還是Socket,在對象上調用Close()都會導致連接操作立即完成(在所有異步完成,異常處理,線程同步等完成後,小於1/10秒)

請注意,在TcpClient的情況下,TcpClient類似乎有一個錯誤,因爲它會拋出NullReferenceException而不是(如預期的那樣)ObjectDisposedException。這似乎是因爲TcpClient在調用Close()時將Client屬性設置爲null,但在調用完成委託時嘗試使用該值。哎呀。

這意味着在您的代碼中,調用者將看到NullReferenceException而不是您似乎想要拋出的Exception。但這似乎並不會造成實際的延遲本身。

這裏是我的測試程序:

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(); 
    } 
} 

不幸的是,你還沒有提供一個實際的完整的代碼示例演示了問題。如果在你的環境中,上面的代碼演示了你所描述的問題,因爲它在我的環境中不這樣做,這顯然意味着你的環境會導致問題。不同的操作系統版本,不同的.NET版本等。

在這種情況下,您應該具體說明可能相關的特定環境方面。

如果上面的代碼示例按照需要工作,並且沒有演示您描述的問題,那麼您只需要弄清楚代碼中存在哪些不同並導致問題。在這種情況下,如果您仍然無法找出問題,那麼您應該發佈a minimal, complete code example來證明問題。

+0

仍然無法正常工作。我在項目屬性中使用VS 2013,NET 4.5.1。贏得8.1完全修補。我剛剛運行你提到的代碼作爲控制檯項目(Release),並且我得到了Socket - > 20s,TcpClient - > 20s,myCode - > 20s。 SS:http://gyazo.com/fb0d640045c18517d2d7524fa9619efe我也問過我的朋友運行你的代碼,結果相同。 – Josh 2015-01-31 23:08:52

+0

對不起......聽起來像你(和你的朋友,現在)正在尋找您的計算機上的一些特定的配置問題。我已經在各種配置中對自己的代碼進行了測試,包括與您的Windows 7計算機匹配的代碼,並且它們都可以正常工作。代碼本身很好,只留下一些特定計算機配置的問題(.NET中的某些問題,或者可能是特定網絡驅動程序和/或硬件配置的問題)。 – 2015-01-31 23:27:27

+0

你會如此善良,編譯上面的代碼爲我發佈二進制文件?我也會嘗試編譯我自己的,並在「新鮮」的Windows 7虛擬機上進行測試。如果你的二進制工作..那麼肯定VS/.NET的問題。 – Josh 2015-02-01 16:02:37