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

我正在使用VSTS 2008 + C#+ .Net 3.5来开发控制台应用程序,并将请求发送到另一台服务器(Windows Server 2008上的IIS 7.0)。 我发现当请求线程数很大(例如2000个线程)时,客户端在调用response =(HttpWebResponse)request.GetResponse()时会收到错误“无法连接到远程服务器失败”。我的困惑是 – 我有将超时设置为一个较大的值,但我在一分钟内得到了这样的失败消息。 我认为即使连接确实比IIS可以服务的更大,客户端也不应该这么快就得到这样的失败消息,它应该在超时期后得到这样的消息。 任何意见? 有什么想法有什么不对? 是否有任何想法可以使IIS 7.0提供更多并发连接?

这是我的代码,

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; } } 

Kev已经回答了你的问题,我只是想补充说,创建这么multithreading并不是真正好的设计解决方案(只是上下文切换开销是一个很大的减号)加上它不会很好地扩展。

快速回答是:使用异步操作来读取数据而不是创建一堆线程。 或至少使用线程池(和较低的工作线程计数)。 请记住,与一个来源的更多连接只会加速到某种程度。 尝试对它进行基准测试,您将看到可能3-5个连接将比您现在使用的2000更快。

您可以在此处阅读有关异步客户端/服务器体系结构(IOCP – 输入/输出完成端口)及其优点的更多信息。 你可以从这里开始:

MSDN – 使用异步服务器套接字

MSDN – 异步服务器套接字示例

CodeProject – multithreading.NET TCP服务器示例

所有这些示例都使用较低级别的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); 

未经测试,可能需要一些调整。

我估计你已经超出了网站的应用程序池队列。 默认值为1000个请求,您可以同时使用或多或少的2000个请求充斥服务器。 增加超时不会解决这个问题。

尝试增加站点所在应用程序池的队列长度。

您应该尝试捕获基础HTTP状态,这将为您提供有关实际情况的线索。

更新:

当我运行你的代码并尝试下载一个相当大的文件(200MB)时,我得到(503) Server Unavailable. 。 增加应用程序池的请求队列的大小解决了这个问题(我将我的设置为10000)。

我只看到一次Unable to connect to remote server ,遗憾的是无法复制。 这个错误听起来像是在TCP / IP层上出现了问题。 你可以发布完整的例外吗?

转到智能线程池并下载代码。 它是一个实例线程池,用于约束线程数。 在连接到Web服务器和SQL服务器的应用程序中,.Net线程池可能会出现问题。

将循环更改为此

 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个线程。 调整此值直到性能开始降低。 太multithreading比太少更糟糕。 你们很多人发现这是最佳的。

同时将此添加到您的配置中。 值100是我使用的默认值。 有一种方法可以在代码中执行此操作,但语法现在让我失望了。

      

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