views:

759

answers:

8

I am connecting to a 3rd party server. I know right now they allow 8 connections from the same remote user. However i dont know if they will raise or lower the connection limit. So i want my app to dynamically find out. How can i do this?

I'm using C#, MSVS 2008

I started a bounty for anyone who can give me working C#. If no one does then i'll give it to the best answer.

I find this very difficult to do and had a few failed attempts :(

+8  A: 

That's not information which a server gives out to clients by default. The only way to know is keep opening connections until it fails (bad idea), or ask the server owner to offer a service you can poll which returns this information.

Edit: after thinking some more about this question, I'm not sure if it's possible to determine this via "probing" with any real degree of accuracy. If the server returned 503 Server Busy when it reached its connection limit (which I assumed would happen when I made my original suggestion), it would be easier to test. But generally when servers go over their connection limit, they simply don't respond until a new connection is available. The client simply waits for a response. There is no hard way to distinguish between a server which took 10 seconds to respond because its connection limit had been reached, and a server which took 10 seconds to respond for any other reason.

In addition, even if you still attempted to test it in this manner, the requests you make to the server would need to stay open long enough to ensure that the first connection you create (and all subsequent ones) are still open when the nth request times out. That would mean either calling a service which takes an arbitrarily long time to return - a long-running process or a Thread.Sleep(); or download an inconveniently large file. Either approach is extremely inefficient at best.

Rex M
How do i open connections to find the amount that fails? i can see myself making a mistake and reusing the first few connections (bc the transfer was done) after checking the last connection and getting the wrong result.server to poll is ideal. I'll see if they'll offer that.
acidzombie24
@acidzombie put your HttpWebRequest code in a loop and increment a counter. put the whole thing in a try-catch, since HttpWebRequest will throw an exception if it tries to connect and fails.
Rex M
I did it wrong, i was expecting an exception but instead my thread slept for a long time instead. http://www.pastie.org/451086 i tried putting a tryblock in the func and it didnt do anything different.
acidzombie24
@acidzombie use BeginGetResponse instead of GetResponse. That will put the request/response on another thread instead of blocking until the response comes back.
Rex M
The server administrator side of me is crying right now.
Nicholas H
@Nicholas aye, it's important to understand *how* this would work from a technical standpoint, but just as important to understand that you should not ever do it! :)
Rex M
Haha. I still need to know. I need to test the status of a few hundred items and i want to spawn enough threads and connections to maximize the speed and no more. Thus i need to know the remote amount.
acidzombie24
@acidzombie this still seems to be something best done by asking the host
Rex M
Rex M: I guess i should. But those guys are flaky. I'll just i have my app ask my server how many connections i believe they allow instead.
acidzombie24
A: 

Some PSEUDO code here:

connection = MakeNewConnection("ServerAddress");
while (connection.connected)
{
connectionCounter++;
connection = MakeNewConnection("ServerAddress");
}

In the end, your connectionCounter should contain the total connections you can make.If you like, I could actually see what kind of C# code this would need.

PS. It is not a very nice thing to do to a server, and it will probably get you banned within a day :P.

Wim Haanstra
Do you know the actual C# code? i tried http://www.pastie.org/451086 and it slept forever instead of throw an exception.
acidzombie24
A: 

Well if the server you are connecting to is a Windows box and is running WMI, you could just figure out which registry key this information is stored in and get the information there. That is, if the user you connect with has WMI permissions.

Alex
A: 
int counter = 0;
while(true) {

     try{
            Open New Connection
            counter++;

        }
        catch()
        {
           Trace.WriteLine(counter);
        }
}

Gotta love using exceptions for control flow ;)

Chad Grant
That doesn't actually work. If the server is throttling connections, "open new connection" just takes longer, doesn't throw.
Rex M
@Rex You don't know that, he doesn't even specify if the server is refusing connections or throttling them. You don't even know what OS the server is or even what protocol. Thanks for the crappy negative comment AGAIN. Go stalk someone else.
Chad Grant
+2  A: 

a poor-man's way of doing it would be to shell to netstat, grab the stdout, and examine it. it gives you a snapshot of the current connections to other computers. from this you can determine how many times you're connected to a specific server.

-don

Don Dickinson
A: 

I can't comment :) but Don's answer is a solid one. Depending how long you need to monitor the service for you can just schedule netstat to pipe out to a file and at the end of the time period review the data.

To clean up the output data to see just what you want might take a combination of logparser and or excel.

The good thing about netstat is that you can eliminate 'chatter' and just see connections that are connected to the process of interest (by pid).

Otherwise, you can monitor the number of connections to a server using tcp via tcpv4 (or v6) perfmon counters. This connections will include all connections to server, but you might be able to get a rough idea of what your looking for.

Zach Bonham
+1  A: 

The better idea in your case is probably to not really care. I would try opening connections one by one and examining the performance of the application. As long as the performance increases by opening another connection, continue opening new ones. When performance stop increasing you are reasonably close to the optimal number of connections.

erikkallen
+1  A: 

I will take this bounty good sir. Not exactly sure why you want to do this and why someone allows 8 connections.

Defined in 1999 (RFC 2616) “clients that use persistent connections should limit the number of simultaneous connections that they maintain to a given server. A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy. A proxy SHOULD use up to 2*N connections to another server or proxy, where N is the number of simultaneously active users. These guidelines are intended to improve HTTP response times and avoid congestion.” Since developers are using AJAX or AJAX-like requests to update a Web page the http limits are discussed more and more.

Like the RFC says, I was only able to get 2 open connections to web servers.

But here's the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;

namespace ConnectionTest
{
    public class RequestCounter
    {
        public int Counter = 0;
        public void Increment()
        {
            Interlocked.Increment(ref Counter);
        }
    }

    public class RequestThread
    {
        public AutoResetEvent AsyncWaitHandle { get; private set; }
        public RequestCounter RequestCounter;
        public String Url;
        public HttpWebRequest Request;
        public HttpWebResponse Response;

        public RequestThread(AutoResetEvent r, String u, RequestCounter rc)
        {
            Url = u;
            AsyncWaitHandle = r;
            RequestCounter = rc;
        }

        public void Close()
        {
            if (Response != null)
                Response.Close();

            if (Request != null)
                Request.Abort();
        }
    }

    public class ConnectionTest
    {
        static void Main()
        {
            string url = "http://www.google.com/";
            int max = GetMaxConnections(25, url);
            Console.WriteLine(String.Format("{0} Max Connections to {1}",max,url));
            Console.ReadLine();
        }

        private static int GetMaxConnections(int maxThreads, string url)
        {
            RequestCounter requestCounter = new RequestCounter();

            List<RequestThread> threadState = new List<RequestThread>();
            for (int i = 0; i < maxThreads; i++)
                threadState.Add(new RequestThread(new AutoResetEvent(false), url, requestCounter));

            List<Thread> threads = new List<Thread>();
            foreach (RequestThread state in threadState)
            {
                Thread t = new Thread(StartRequest);
                t.Start(state);
                threads.Add(t);
            }

            WaitHandle[] handles = (from state in threadState select state.AsyncWaitHandle).ToArray();
            WaitHandle.WaitAll(handles, 5000); // waits seconds

            foreach (Thread t in threads)
                t.Abort();

            foreach(RequestThread rs in threadState)
                rs.Close();

            return requestCounter.Counter;
        }

        public static void StartRequest(object rt)
        {
            RequestThread state = (RequestThread) rt;
            try
            {
                state.Request = (HttpWebRequest)WebRequest.Create(state.Url);
                state.Request.ReadWriteTimeout = 4000; //Waits 4 seconds

                state.Response = (HttpWebResponse)state.Request.GetResponse();
                if (state.Response.StatusDescription.Equals("OK", StringComparison.InvariantCultureIgnoreCase))
                    state.RequestCounter.Increment();

                //Do not close, or you will free a connection. Close Later
                //response.Close(); 
            }
            catch (WebException e)
            {
                //Console.WriteLine("Message:{0}", e.Message);
                state.Close();
            }
            catch (ThreadAbortException e)
            {
                //Console.WriteLine("Thread Aborted");
                state.Close();
            }
            catch(Exception e)
            {
                //Console.WriteLine("Real Exception");    
                state.Close();
            }
            finally
            {
                state.AsyncWaitHandle.Set();
            }
        }
    }
}
Chad Grant
Thank you so much :D
acidzombie24