Search code examples
c#.netvisual-studio-2008iis-7httpwebrequest

"Unable to connect to remote server fail" in HttpWebRequest


I am using VSTS 2008 + C# + .Net 3.5 to develop a console application and I send request to another server (IIS 7.0 on Windows Server 2008). I find when the # of request threads are big (e.g. 2000 threads), the client will receive error "Unable to connect to remote server fail" when invoking response = (HttpWebResponse)request.GetResponse().My confusion is -- I have set timeout to be a large value, but I got such fail message within a minute. I think even if the connection are really larger than what IIS could serve, client should not get such fail message so soon, it should get such message after timeout period. Any comments? Any ideas what is wrong? Any ideas to make more number of concurrent connection being served by IIS 7.0?

Here is my code,

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

Solution

  • Kev answered you question already, I just want to add that creating so many threads is not really good design solution (just context switching overhead is a big minus) plus it won't scale good.

    The quick answer would be: use asynchronous operations to read data instead of creating a bunch of threads. Or at least use thread pool (and lower worker thread count). Remember that more connections to one source will only speed things up till some degree. Try benchmarking it and you will see that probably 3-5 connections will work faster that 2000 you are using now.

    You can read more about asynchronous client/server architecture (IOCP - input/output completion ports) and its advantages here. You can start from here:

    MSDN - Using an Asynchronous Server Socket

    MSDN - Asynchronous Server Socket Example

    CodeProject - Multi-threaded .NET TCP Server Examples

    All of these examples uses lower level TCP object, but it can be applied to WebRequest/WebResponse as well.

    UPDATE

    To try thread pool version, you can do something like this:

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

    Not tested, may need some adjustment.