2009-10-21 101 views
1

我使用VSTS 2008 + C#+。NET 3.5的開發控制檯應用程序,我請求發送到另一臺服務器(Windows Server 2008上的IIS 7.0)。我發現當請求線程數很大時(例如2000個線程),當調用response =(HttpWebResponse)request.GetResponse()時,客戶端將收到錯誤「無法連接到遠程服務器失敗」。我的困惑是 - 我有設置超時值是一個很大的值,但是我在一分鐘之內就收到了這樣的失敗信息。我認爲,即使連接真的大於IIS可以提供​​的連接數,客戶端也不應該這麼快得到這樣的失敗消息,它應該在超時時間後得到這樣的消息。任何意見?任何想法有什麼不對?任何想法讓更多數量的併發連接由IIS 7.0提供服務?「無法連接到遠程服務器失敗」中的HttpWebRequest

這裏是我的代碼,

class Program 
    { 
     private static int ClientCount = 2000; 
     private static string TargetURL = "http://labtest/abc.wmv"; 
     private static int Timeout = 3600; 

     static void PerformanceWorker() 
     { 
      Stream dataStream = null; 
      HttpWebRequest request = null; 
      HttpWebResponse response = null; 
      StreamReader reader = null; 
      try 
      { 
       request = (HttpWebRequest)WebRequest.Create(TargetURL); 
       request.Timeout = Timeout * 1000; 
       request.Proxy = null; 
       response = (HttpWebResponse)request.GetResponse(); 
       dataStream = response.GetResponseStream(); 
       reader = new StreamReader(dataStream); 

       // 1 M at one time 
       char[] c = new char[1000 * 10]; 

       while (reader.Read(c, 0, c.Length) > 0) 
       { 
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId); 
       } 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex.Message + "\n" + ex.StackTrace); 
      } 
      finally 
      { 
       if (null != reader) 
       { 
        reader.Close(); 
       } 
       if (null != dataStream) 
       { 
        dataStream.Close(); 
       } 
       if (null != response) 
       { 
        response.Close(); 
       } 
      } 
     } 

     static void Main(string[] args) 
     { 
      Thread[] workers = new Thread[ClientCount]; 
      for (int i = 0; i < ClientCount; i++) 
      { 
       workers[i] = new Thread((new ThreadStart(PerformanceWorker))); 
      } 

      for (int i = 0; i < ClientCount; i++) 
      { 
       workers[i].Start(); 
      } 

      for (int i = 0; i < ClientCount; i++) 
      { 
       workers[i].Join(); 
      }   

      return; 
     } 
    } 
+1

我已經更新了我的回答,您可以粘貼完整的例外呢? – Kev 2009-10-21 06:22:04

回答

3

千電子伏回答你已經問,我只想補充一點,創造這麼多線程是不是真的很好的設計解決方案(只是一個上下文切換的開銷是很大的負),再加上它不能擴展好。

快速回答是:使用異步操作讀取數據而不是創建一堆線程。或者至少使用線程池(和較低的工作線程數)。請記住,連接到一個源的更多連接只會在某種程度上加快速度。嘗試對它進行基準測試,你會發現,你現在使用的2000可能會以更快的速度連接3-5個連接。

您可以在這裏閱讀更多關於異步客戶機/服務器體系結構(IOCP - 輸入/輸出完成端口)及其優點。你可以從這裏開始:

MSDN - Using an Asynchronous Server Socket

MSDN - Asynchronous Server Socket Example

這些例子

CodeProject - Multi-threaded .NET TCP Server Examples

全部使用低級別TCP對象,但它可以被應用到的WebRequest/WebResponse的爲好。

UPDATE

要嘗試線程池的版本,你可以做這樣的事情:

ManualResetEvent[] events = new ManualResetEvent[ClientCount]; 
for (uint cnt = 0; cnt < events.Length; cnt++) 
{ 
    events[cnt] = new ManualResetEvent(false); 
    ThreadPool.QueueUserWorkItem(obj => PerformanceWorker()); 
} 

WaitHandle.WaitAll(events); 

沒有測試,可能需要一些調整。

+0

我想模擬(做性能測試)場景時,有大量的併發連接數。使用線程池可以比使用真正的併發線程更好地模擬這個嗎? – George2 2009-10-21 09:26:19

+1

你應該自己嘗試一下。我不確定在這種情況下它是否會有利於你(因爲這是用於負載測試,所以不是真正的性能重要),但你會學到一些新的東西( - 。 使用線程池示例更新了答案。 – Audrius 2009-10-21 10:19:07

+0

我在這裏有一個相關的問題,很感激,如果你可以看看。謝謝http://stackoverflow.com/questions/1600002/configure-iis-7-0-meta-database-issue – George2 2009-10-21 10:38:30

2

我想你已經刷爆了該網站的應用程序池隊列。默認情況下是1000個請求,你用2000多個請求一次全部涌入服務器。增加超時並不能解決這個問題。

嘗試增加隊列長度爲站點駐留在應用程序池。

你應該嘗試捕捉潛在的HTTP狀態,這會給你一個線索,什麼是怎麼回事。

更新:

當我運行你的代碼,並嘗試下載一個相當大的文件(200MB)我得到(503) Server Unavailable.。增加應用程序池的請求隊列的大小解決了這個問題(我將我的設置爲10000)。

只有一回,我看到Unable to connect to remote server和可悲的是已經無法複製。這個錯誤聽起來像是TCP/IP層出現問題。你能發佈完整的例外嗎?

+0

謝謝! 1.我已將它增加到65535.我認爲你的意思是IIS管理器=>應用程序池=>高級設置=>隊列長度。這是你設定的正確的地點和價值嗎? 2.對於基礎Http狀態,如何獲取它? – George2 2009-10-21 05:18:01

+2

就像我在iis.net論壇上評論的那樣,HTTP錯誤日誌包含這些信息。 – 2009-10-21 06:11:57

+0

感謝Kev,因爲「應用程序池的請求隊列解決了這個問題」,你的意思是IIS管理器=>應用程序池=>高級設置=>隊列長度? – George2 2009-10-21 06:23:54

1

轉到Smart Thread Pool並下載代碼。它是一個約束線程數的實例線程池。 .Net線程池可能在連接到Web服務器和SQL服務器的應用程序中存在問題。

循環改成這樣

static void Main(string[] args) 
     { 
      var stp = new SmartThreadPool((int) TimeSpan.FromMinutes(5).TotalMilliseconds, 
              Environment.ProcessorCount - 1, Environment.ProcessorCount - 1); 
      stp.Start(); 
      for (var i = 0; i < ClientCount; i++) 
      { 
       stp.QueueWorkItem(PerformanceWorker); 
      } 
      stp.WaitForIdle(); 
      stp.Shutdown(); 

      return; 
     } 

這限制了線程池來使用PROC每1個線程。調整它直到性能開始下降。太多的線程比太少。你很多人發現這是最佳的。

此外,添加到您的配置。 100的值是我使用的默認值。有一種方法可以在代碼中做到這一點,但語法現在轉義了我。

<system.net> 

    <connectionManagement> 

     <add address=「*「 maxconnection=「100「 /> 

    </connectionManagement> 

</system.net> 
+0

智能線程池無法打開。我在網上搜索了一些,你的意思是這個嗎? http://www.codeproject.com/KB/threads/smartthreadpool.aspx – George2 2009-10-22 06:39:12

+0

爲什麼「.Net線程池可能在連接到Web服務器和SQL服務器的應用程序中出現問題。」? – George2 2009-10-22 06:39:50

0

我使用Visual Studio 2005中如何發送短信,這裏是我的代碼:

IPHostEntry host; 
host = Dns.GetHostEntry(Dns.GetHostName()); 
UriBuilder urlbuilder = new UriBuilder(); 
urlbuilder.Host = host.HostName; 
urlbuilder.Port = 4719; 
string PhoneNumber = "9655336272"; 
string message = "Just a simple text"; 
string subject = "MMS subject"; 
string YourChoiceofName = "victoria"; 
urlbuilder.Query = string.Format("PhoneNumber=%2B" + PhoneNumber + "&MMSFrom=" + YourChoiceofName + "&MMSSubject=" + subject + "&MMSText=" + message);//+ "&MMSFile=http://127.0.0.1/" + fileName 
HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(urlbuilder.ToString(), false)); 
HttpWebResponse httpResponse = (HttpWebResponse)(httpReq.GetResponse()); 
相關問題