22

C# 2008 SP1

I am using this code to connect to our client website. This is for a softphone application. Before the user makes a call, the softphone has to test if there is an active Internet connection.

So, want I have done is used the httpWebRequest class to connect to our clients website. If the response is ok, then the Internet connection can proceed.

However, I have noticed that the response is taking too long to respond. I am not sure if this is not a very efficient way to test.

However, when I browse to their website, it takes less than a second to load the page. But takes too long when I use the HttpWebRequest class

So requirements for this are:

Sometime a proxy will be used at the client's office. To I can't use the TCPClient class (doesn't have a proxy property).

The proxy doesn't support SOCKS so cannot use the Sockets class.

I need to use a timeout property. So cannot use the WebClient class. This is because the softphone would freeze until a response is returned. So timeout after a few seconds.

So the only one I can think of is the HttpWebRequest class.

  HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.xxxxxxxxx.com");
            request.Timeout = 5000;
            request.Credentials = CredentialCache.DefaultNetworkCredentials;
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            if (response.StatusCode == HttpStatusCode.OK)
            {
                Console.WriteLine("IsSIPServerAvailable: " + response.StatusCode);
                isAvailable = true;
            }

======== Edit using p\Invoke ====

 [DllImport("wininet.dll", CharSet = CharSet.Auto)]
    private extern static bool InternetGetConnectedState(ref InternetConnectionState_e lpdwFlags, int dwReserved);

 [Flags]
    enum InternetConnectionState_e : int
    {
        INTERNET_CONNECTION_MODEM = 0x1,
        INTERNET_CONNECTION_LAN = 0x2,
        INTERNET_CONNECTION_PROXY = 0x4,
        INTERNET_RAS_INSTALLED = 0x10,
        INTERNET_CONNECTION_OFFLINE = 0x20,
        INTERNET_CONNECTION_CONFIGURED = 0x40
    }

 // In function for checking internet
 InternetConnectionState_e flags = 0;          
 bool isConnected = InternetGetConnectedState(ref flags, 0);
Yahia
  • 69,653
  • 9
  • 115
  • 144
ant2009
  • 27,094
  • 154
  • 411
  • 609

7 Answers7

16

Try using P/Invoke to call InternetGetConnectedState. That should tell you whether or not you have a connection configured. You can then try checking the specific connection to your service using InternetCheckConnection. This is (sometimes) quicker than hooking up the connection directly, but I'd test it to see if it's any better than just doing a full connection up front.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 3
    The downside with that (IMO) is that it only tells you whether the computer is connected to "the internet in general". It's only somewhat indicative of whether you'll be able to get to the particular service you're after. The best way to do that, IMO, is to connect to that very service. Of course that won't guarantee that it'll still be valid a second later, but I think it's a better indicator if it's possible. (In some cases it's not, for instance if just connecting incurs some sort of charge.) – Jon Skeet May 09 '09 at 19:36
  • 1
    I have edited my code for the p/Invoke. However, it does tell me if the LAN is connected to my computer (plugged in or out). However, it cannot tell me if I have an active Internet connection (browse the Internet). – ant2009 May 09 '09 at 20:06
  • @robUK: I edited my answer to include the call to InternetCheckConnection. That's another P/Invoke you can try - it should tell you whether that specific URL is available, but I believe it's slightly faster than trying to hook up a connection yourself. – Reed Copsey May 10 '09 at 18:29
11

What is the softphone going to use for its real communication? Is that going over HTTP/HTTPS to the same web site? If so, that's absolutely the right way to go - the next step is to work out why it's taking so long.

Is the network connection definitely up before you may the request? Are you definitely not making any requests beforehand? I ask because I notice you're not disposing of the response - if that happens elsewhere as well, you may find that you're running up against the connection pool only giving you a couple of connections to a particular server. The moral is to always put HttpWebResponses in a using statement. Of course, that may well not be the problem in your case, but it's worth a try.

If your actual application is going to connect elsewhere, then that's where your test should check as well. Basically, make it as close to the real thing as possible.

Out of interest, you say it's a "softphone" application - is this actually running on a phone of some description, using the compact framework, or is it a desktop app?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Hello. Its a desktop running which can run on 2000, XP, and Vista. That for the info on the using statement. I forgot that. The SIP server is on the same server. However, I can connecting using SIP protocol and streaming using RTP. – ant2009 May 09 '09 at 18:55
  • If you're actually going to be connecting with SIP later, why not connect with SIP for the test? Is there some no-op SIP request you can make? – Jon Skeet May 09 '09 at 19:12
  • I am looking into some SIP requests. I also like the P/invoke option below. I think I will experiment will both options. thanks. – ant2009 May 09 '09 at 19:15
6

I had a similar situation where we were going to make a WCF call to a client and it would take too long if the client wasn't reachable (for whatever reason). What I did was open a raw TCP socket to the client address... This fails quickly if the client is not listening at the port (in your case port 80) and succeeds quickly if they are there.

This gave me the fastest and most accurate answer to determine if I would be able to communicate with the endpoint that I was trying to reach. The only down side of this is that you have to manage the timeout yourself on the socket because there are only options for Send and Receive timeouts not connect.

It goes something like this...

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    try
    {
         IAsyncResult result = socket.BeginConnect("www.xxxxxxxxx.com", 80, null, null );
         //I set it for 3 sec timeout, but if you are on an internal LAN you can probably 
         //drop that down a little because this should be instant if it is going to work
         bool success = result.AsyncWaitHandle.WaitOne( 3000, true );

         if ( !success )
         {
                throw new ApplicationException("Failed to connect server.");
         }

         // Success
         //... 
    }
    finally
    {
         //You should always close the socket!
         socket.Close();
    }

I don't have the actual code that I used in front of me, but this should put you on the general path.

Brian ONeil
  • 4,229
  • 2
  • 23
  • 25
  • Hello, thanks for the code. Actually I have already tried the sockets class. However, the proxy server that I have to connect through doesn't support the SOCKS protocol. If it wasn't for the proxy server, this would be a great solution. – ant2009 May 11 '09 at 02:18
  • ONiel, Thanks for this. I was using a TcpClient, and it was much much slower then this method. – Art W Dec 04 '10 at 07:44
  • Many thanks from this Googler! I was trying to find out if port 25 (mail server port) was blocked by the provider so I can use port 2525. Your code cut that process from a 30 second wait to a 3 second wait. :) – knight666 Oct 08 '11 at 14:49
2

You can reference the Microsoft.VisualBasic.Devices namespace to use the NetworkAvailableEventHandler delegate and Network class. I use Network.IsAvailable property and Network.NetworkAvailabilityChanged event to check that the network is there (or is affected later), and then do an HTTP GET to my server to see if the server is there.

This helps with reporting the issue a bit more specifically, instead of "can't see network".

Richard Watson
  • 2,584
  • 1
  • 23
  • 30
1

A better option is to add reference to the Microsoft.VisualBasic and add a using statement Microsoft.VisualBasic.Device then you can use the following line of code to check for connection to any network at all.

public static bool isConnectedToNetwork {
   get {
      Network network = new Network();
      return network.IsAvailable;
   }
}
Daniel Kurz
  • 816
  • 7
  • 21
1

Use Exception Handling.

        try
        {
            using (WebClient client = new WebClient())
            {
                string htmlCode = client.DownloadString("https://www.google.com/");                    
            }
        }
        catch
        {
            //No Internet 
            Console.WriteLine("No Internet")
        }
Naresh Bisht
  • 645
  • 6
  • 16
0

request.GetResponse() itself will give you an exception if the host name can't be resolved, though, so you might want to put a try-catch around that, catch System.Net.WebException, and check its error status in the Status property. I'm not sure which statuses exactly would indicate no internet, though; most responses could just as well be due to dns or other connection problems.

Nyerguds
  • 5,360
  • 1
  • 31
  • 63