[C#]平行處理網路傳輸時因連線數不足發生連線Timeout的解決方案

  • 15716
  • 0
  • C#
  • 2012-05-27

[C#]平行處理網路傳輸時因連線數不足發生連線Timeout的解決方案

最近專案程式發生了一個很奇妙的BUG,專案程式在某些情況下網路傳輸會發生Timeout的現象,而且一發生就是一連串的網路傳輸都連帶Timeout。這問題很難重現,程式看起來邏輯都對,在大部分的情況下都看不到這種現象,開發團隊的電腦也沒有一台發生。後來查了一下網路文章,大膽推測是因為連線數過多造成的,可能是某些狀況下程式會同時有多個網路傳輸的連線,導致超過可容納的連線數造成等待而Timeout。

 

MSDN中的ServicePointManager.DefaultConnectionLimit 屬性這篇有提到,ServicePointManager.DefaultConnectionLimit在一般的WinForm程式中預設是2,而在ASP.NET中預設是10,而ServicePointManager.DefaultConnectionLimit這個屬性值又是HttpWebRequet.ServicePoint.ConnectionLimit的預設值,也就是說在WinForm下同時只能服務兩個連線數,超過兩個以上的連線自然就會被卡住而最後導致Timeout。

 

因此解決方法不外乎就是設定ServicePoint.ConnectionLimit的值,或是直接修改ServicePointManager.DefaultConnectionLimit,從預設值開始下手調整。這邊筆者附上完整的測試程式。


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Threading;

namespace ConsoleApplication15
{
	class Program 
	{
		public static string url = "https://www.google.com/images/srpr/logo3w.png";
		private static List<WaitHandle> finished = new List<WaitHandle>();
		public static void Main()
		{
			ServicePointManager.DefaultConnectionLimit = 200;   
			finished.Clear();
			for (var idx = 0; idx < 5; ++idx )
			{
				finished.Add(new ManualResetEvent(false));
				Download(idx, url);
			}
			WaitHandle.WaitAll(finished.ToArray());
			Console.WriteLine("Done...");   
		}    

		private static void Download(int idx, string url)
		{
			var wc = new WebClient();
			wc.OpenReadCompleted += wc_OpenReadCompleted;
			wc.OpenReadAsync(new Uri(url), idx);
		}

		private static void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
		{
			Console.WriteLine(string.Format("{0}: Download Completed", e.UserState));

			var idx = (int)e.UserState;
			var manualResetEvent = finished[idx] as ManualResetEvent;

			Debug.Assert(manualResetEvent != null, "manualResetEvent != null");
			manualResetEvent.Set();
		}     
	}
}

 

注意到裡面有一段ServicePointManager.DefaultConnectionLimit = 200;的程式,若是把它給Mark起來,我們可以發現運行起來程式會跑兩個網路傳輸就卡住了。

image

 

若是將Mark拿掉,程式就可以把所有的網路傳輸正常的跑完。

image

 

Link