Skip to main content
 首页 » 编程设计

c#之HttpWebRequest 中的 "Unable to connect to remote server fail"

2024年01月29日27kevingrace

我正在使用 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 已经回答了你的问题,我只是想补充一点,创建这么多线程并不是真正好的设计解决方案(只是上下文切换开销是一个很大的减号)而且它不会很好地扩展。

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

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

MSDN - Using an Asynchronous Server Socket

MSDN - Asynchronous Server Socket Example

CodeProject - Multi-threaded .NET TCP Server Examples

所有这些示例都使用较低级别的 TCP 对象,但它也可以应用于 WebRequest/WebResponse。

更新

要尝试线程池版本,你可以这样做:

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

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