C# Socket.Connect連線請求超時機制
阿新 • • 發佈:2019-01-26
作者:RazanPaul
譯者:Todd Wei
原文:http://www.codeproject.com/KB/IP/TimeOutSocket.aspx
轉自:http://hi.baidu.com/wf_studio/blog/item/d0a339f4c70c9ae57609d7c9.html
介紹
您可能注意到了,.Net的System.Net.Sockets.TcpClient和System.Net.Sockets.Socket都沒有直接為Connect/BeginConnect提供超
時控制機制。因此,當伺服器未處於監聽狀態,或者發生網路故障時,客戶端連線請求會被迫等待很長一段時間,直到丟擲異常。默
認的等待時間長達20~30s。.Net Socket庫的SocketOptionName.SendTimeout提供了控制傳送資料的超時時間,但並非本文討論的連
接請求的超時時間。
背景
這個問題最初源於我的某個專案,在解決以後,我曾將關鍵程式碼發表在自己的部落格上。我注意到不少人對此表示感謝,所以我想這是
一個常見的問題,或許很多人都需要解決它。
實現
譯者:Todd Wei
原文:http://www.codeproject.com/KB/IP/TimeOutSocket.aspx
轉自:http://hi.baidu.com/wf_studio/blog/item/d0a339f4c70c9ae57609d7c9.html
介紹
您可能注意到了,.Net的System.Net.Sockets.TcpClient和System.Net.Sockets.Socket都沒有直接為Connect/BeginConnect提供超
時控制機制。因此,當伺服器未處於監聽狀態,或者發生網路故障時,客戶端連線請求會被迫等待很長一段時間,直到丟擲異常。默
認的等待時間長達20~30s。.Net Socket庫的SocketOptionName.SendTimeout提供了控制傳送資料的超時時間,但並非本文討論的連
接請求的超時時間。
背景
這個問題最初源於我的某個專案,在解決以後,我曾將關鍵程式碼發表在自己的部落格上。我注意到不少人對此表示感謝,所以我想這是
一個常見的問題,或許很多人都需要解決它。
實現
下面是實現的關鍵程式碼:
class TimeOutSocket { private static bool IsConnectionSuccessful = false; private static Exception socketexception; private static ManualResetEvent TimeoutObject = new ManualResetEvent(false); public static TcpClient Connect(IPEndPoint remoteEndPoint, int timeoutMSec) { TimeoutObject.Reset(); socketexception = null; string serverip = Convert.ToString(remoteEndPoint.Address); int serverport = remoteEndPoint.Port; TcpClient tcpclient = new TcpClient(); tcpclient.BeginConnect(serverip, serverport, new AsyncCallback(CallBackMethod), tcpclient); if (TimeoutObject.WaitOne(timeoutMSec, false)) { if (IsConnectionSuccessful) { return tcpclient; } else { throw socketexception; } } else { tcpclient.Close(); throw new TimeoutException("TimeOut Exception"); } } private static void CallBackMethod(IAsyncResult asyncresult) { try { IsConnectionSuccessful = false; TcpClient tcpclient = asyncresult.AsyncState as TcpClient; if (tcpclient.Client != null) { tcpclient.EndConnect(asyncresult); IsConnectionSuccessful = true; } } catch (Exception ex) { IsConnectionSuccessful = false; socketexception = ex; } finally { TimeoutObject.Set(); } } }
這裡,ManualResetEvent的WaitOne(TimeSpan, Boolean)起到了主要的作用。它將阻止當前執行緒,直到ManualResetEvent物件被Set
或者超過timeout時間。上面的程式碼中,呼叫BeginConnect後通過WaitOne方法阻止當前執行緒,如果在timeoutMSec時間內連線成功,
將在CallBackMethod回撥中呼叫TimeoutObject.Set,解除被阻塞的連線執行緒並返回;否則,連線執行緒會在等待超時後,主動關閉連
接並丟擲TimeoutException。