介紹在發送 Request 時如未正確的關閉連線會造成的問題與解決方法。
前言
這次案例是發生在原本在網站下有一段程式會持續發送大量 Request 至另一個網站,而這段程式在網站下執行時是正常的,但是後來將這段程式移到 Console / WinForm 時,就發生了原本發送 Request 的程式竟然出現了大量 Timeout 例外錯誤,但是實際執行該網站連結卻是正常的。
經過查詢後,發現該發送 Request 程式在處理 GetResponse() 方法後並未呼叫 Close() 方法關閉連線,以致連線數持續被佔據而後面其他連線自然就無法處理而等待到 Timeout 發生,另外在 MSDN 提到 DefaultConnectionLimit 屬性預設的連線數為 2 ,但在 ASP.NET 中預設連線數為 10 ,所以如需大量發送 Request 的情況下可以視情況調整連線數量。
測試範例
建立一個 Console 應用程式,加入以下程式碼
static void Main(string[] args)
{
for (int i = 0; i < 20; i++)
{
try
{
WebRequest request = HttpWebRequest.Create("http://www.google.com");
request.Method = "GET";
request.Timeout = 3000;
WebResponse response = request.GetResponse();
//response.Close();
Console.WriteLine("OK!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
以上程式碼可以看到 response.Close() 被暫時註解了,因目前要用於之後測試連線數,直接將此程式碼進行執行後可以看到以下結果。
上圖可以看到在預設連線數 2 下,發送了 2 Request 請求後之後的連線就全部 Timeout 了,接著透過 ServicePointManager 類別的 DefaultConnectionLimit 屬性調整連線數量為 10 ,如下
static void Main(string[] args)
{
// 調整連線數量
ServicePointManager.DefaultConnectionLimit = 10;
for (int i = 0; i < 20; i++)
{
try
{
WebRequest request = HttpWebRequest.Create("http://www.google.com");
request.Method = "GET";
request.Timeout = 3000;
WebResponse response = request.GetResponse();
//response.Close(); // 暫時先不關閉連線
Console.WriteLine("OK!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
同樣進行測試,結果會看到當發送 10 個 Request 請求後一樣出現了 Timeout 的情況,如下
最後將呼叫 Close() 方法的註解取消,讓在呼叫 GetResponse() 方法後正常的關閉連線,經過測試後 Request 請求的動作恢復正常,如下。
結論,在撰寫程式碼的時候,需要多注意物件是否有正確釋放或關閉,雖然本次案例在網站下執行時看似正常,但是在未關閉連線的情況下卻會多佔據其他想要使用的連線數並且造成效能的消耗,因此需要多多注意。
參考資料
ServicePointManager.DefaultConnectionLimit 屬性
以上文章敘述如有錯誤及觀念不正確,請不吝嗇指教
如有侵權內容也請您與我反應~謝謝您 :)