“无法连接到远程服务器失败”中的HttpWebRequest

“无法连接到远程服务器失败”中的HttpWebRequest

问题描述:

我使用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

千电子伏回答你已经问,我只想补充一点,创造这么多线程是不是真的很好的设计解决方案(只是一个上下文切换的开销是很大的负),再加上它不能扩展好。

快速回答是:使用异步操作读取数据而不是创建一堆线程。或者至少使用线程池(和较低的工作线程数)。请记住,连接到一个源的更多连接只会在某种程度上加快速度。尝试对它进行基准测试,你会发现,你现在使用的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://*.com/questions/1600002/configure-iis-7-0-meta-database-issue – George2 2009-10-21 10:38:30

我想你已经刷爆了该网站的应用程序池队列。默认情况下是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

转到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

我使用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());