views:

485

answers:

5

Hi,

I'm a bit of newbie to c#/.net development, but I've put together a stock tracking application for a small set of assets in my company. I have also set up the database it connects to in SQL 2000.

It currently works brilliantly when a network connection is available, but I want to expand it for use when I'm away from a connection.

First off I'll need to know if there's a connection available. So I put this together:

    private int availableNetAdapters()
    {
        int nicCount = 0;
        foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
        {
            if (nic.OperationalStatus == OperationalStatus.Up)
            {
                nicCount++;
            }
        }

        return nicCount;
    }

Seems to work, but I have to test for ">1" as something as "MS TCP Loopback interface" is always detected regardless of the other adapter sates.

Is there a better/easier way to check connectivity?

G

+6  A: 

System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()

you can also use the events NetworkAvailabilityChanged and NetworkAddressChanged in that class to monitor IP address and network availability changes.

edit: be aware that this method checks all available network interfaces that may be on the computer (wireless, lan, etc.). If anyone of them is connected, it will return true.

Luke
Correct me if I'm wrong, but won't this enumerate bluetooth as well? That would seem to be an undesirable result.
DannySmurf
Just googled that, and it looks you're right.
Luke
A: 

Just the job. Thanks a lot. So quick too :-) Kind of feel dumb for not managing to find that for myself.

This ignores the "MS TCP Loopback interface" just as I was hoping. Anyone know what that actually is/does?

G-
It would be this: http://en.wikipedia.org/wiki/Loopback. You wouldn't want to use that as a test for connectivity since it will always be connected.
John Price
Sorry... more specifically, the section called "Virtual Network Interface" in that article.
John Price
+7  A: 

Some more things to remember:

  • Avaialable Network connection != Available internet connection.
  • Internet Access != access to a specific web site (think proxy filters, or the site could just be down)

Therefore it's generally best to test for access to the specific resource you need directly.

These resources are volatile; you have to handle the exception when they go down anyway. So it's generally best to just go get a resource as if you know for sure it exists and put your development time in to making sure your exception handler does a nice job with the failures.

Joel Coehoorn
Thanks for the reminders. Would try/catch handling be the best way to choose whether to tun my program in offline mode then? I will look into a method to store this data offline in due course but wan to work out some of this myself :-)
G-
my $0.02 is that the first time you get a failure, prompt the user if they want to retry or go into offline mode. if they go into offline mode, stay in offline mode until they click a button to try to go online again.
rmeador
A: 

We have an application that runs mainly in police cars connected via wireless air cards. We needed a way to determine if they were connected or not. We wrote a very small Ping.cs class that pings a predetermined IP or computer name at a regular intervals. We interpret the result message and change the display of a system tray connection icon. If you want I can send you the C# code.

Ron Skufca
Yes please, I'd like to see that code that sounds very useful to me
G-
I will clean it up and post it here. Hopefully it will be posted in a day depending on my workload.
Ron Skufca
Wouldn't that fall over if that computer ever got removed for some reason? I hope you have it well documented that it is required to be up for the system to keep working.
Jamie Penney
Yes it would but for our applications we host our software on dedicated servers at the customers facilities along with other mission critical applications. We are pinging a server that should never be removed or turned off.
Ron Skufca
+1  A: 

Here's the class

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;

namespace Ping
{    
    public readonly int iSent = 0;
    public readonly int iReceived = 0;
    public readonly int iLost = 0; 

    public PingReceivedArgs (int iSent, int iReceived, int iLost)
    {
        this.iSent = iSent;
     this.iReceived = iReceived;
     this.iLost = iLost;
    }

    public class PingFailedArgs : EventArgs
    {
        public readonly int iSent = 0;
     public readonly int iReceived = 0;
     public readonly int iLost = 0;

     public PingFailedArgs (int iSent, int iReceived, int iLost)
     {
      this.iSent = iSent;
      this.iReceived = iReceived;
      this.iLost = iLost;
     }
    }

/// <summary>
/// The Main Ping Class
/// </summary>
public class Ping
{
     //Create delegate for events
            public delegate void PingReceivedHandler(object DataObj, PingReceivedArgs PingReceived);
     public delegate void PingFailedHandler(object DataObj, PingFailedArgs PingFailed);

 //The events we publish
 public event PingReceivedHandler OnPingReceived;
 public event PingFailedHandler OnPingFailed;

 private void FirePingReceivedEvent( int iSent, int iReceived, int iLost)
 {
  PingReceivedArgs NewStatus = new PingReceivedArgs(iSent, iReceived, iLost);
  if (OnPingReceived != null)
  {
   OnPingReceived(this,NewStatus);
  }
 }

 private void FirePingFailedEvent(int iSent, int iReceived, int iLost)
 {
  PingFailedArgs NewStatus = new PingFailedArgs(iSent, iReceived, iLost);
  if (OnPingFailed != null)
  {
   OnPingFailed(this,NewStatus);
  }
 }


 private string _Host = "";
 private bool _HostFound = false;
 private int _PingSent = 0;
 private int _PingReceived = 0;
 private int _PingLost = 0;
 private int _PauseBetweenPings = 2000;
 private Thread _PingThread;

 public string  Host
 {
  get { return _Host; }
  set { _Host = value; }
 }
 public bool  HostFound
 {
  get { return _HostFound; }
 }
 public int PingSent
 {
  get { return _PingSent; }
 }
 public int PingReceived
 {
  get { return _PingReceived; }
 }
 public int PingLost
 {
  get { return _PingLost; }
 }

 public int  PauseBetweenPings
 {
  get { return _PauseBetweenPings; }
  set { _PauseBetweenPings = value; }
 }

 public Ping()
 {
  //
  // TODO: Add constructor logic here
  //
 }

 public void StartPinging()
 {
  try
  {
   if (_Host.Length == 0)
   {
    //LogStatus.WriteLog("Host name is blank,    stopping.","Error","StartPinging");
    return;
   }


               if (_PingThread == null || (_PingThread.ThreadState &    (System.Threading.ThreadState.Unstarted | System.Threading.ThreadState.Background)) == 0)
   {

    _PingThread = new Thread(new ThreadStart(LoopAndPing));
    _PingThread.IsBackground = true;
    _PingThread.Start();
   }
  }
  catch( Exception ex) 
  {
   //LogStatus.WriteErrorLog(ex,"Error","StartPinging");
  }
 }

 public void StopPinging()
 {
  try
  {
               if (_PingThread != null && (_PingThread.ThreadState &    (System.Threading.ThreadState.Stopped | System.Threading.ThreadState.Aborted |    System.Threading.ThreadState.Unstarted | System.Threading.ThreadState.AbortRequested)) ==    0)
   {
    _PingThread.Abort();
    _PingThread.Join();
   }
  }
  catch (Exception ex)
  {
   //LogStatus.WriteErrorLog(ex, "Error", "StopPinging");
  }
 }

 /// <summary>
 /// LoopAndPing: Runs from a thread.  Basically loops and gathers stats.
 /// </summary>
 private void LoopAndPing()
 {
  bool bHostFound = false;

  try
  {
   while(true)
   {
    _PingSent++;
    bHostFound = PingHost(_Host);
    if (bHostFound) 
    { 
     _PingReceived++; 
     _HostFound = true;
        FirePingReceivedEvent(_PingSent,_PingReceived,_PingLost);
    }
    else  
    { 
     _PingLost++; 
     _HostFound = false;
        FirePingFailedEvent(_PingSent,_PingReceived,_PingLost);
    }
    Thread.Sleep(_PauseBetweenPings);
   }
  }
  catch(ThreadAbortException)
  {
   //No need to do anything!
  }
  catch(Exception e) 
  {
   //LogStatus.WriteErrorLog(e,"Error","LoopAndPing");
  }
 }

 /// <summary>
 /// PingHost - Send one ping to the host
 /// </summary>
 /// <param name="host">Can be an IP or Host name.</param>
 /// <returns></returns>
 public bool PingHost(string szHost)
 {
  bool bPingWorked = false;

  try
  {
   string szCommand = "ping " + szHost + " -n 1";
   Process p = new Process();
   p.StartInfo.FileName = "cmd.exe";
   p.StartInfo.Arguments = "/Q /A /C" + szCommand;
   p.StartInfo.UseShellExecute = false;
   p.StartInfo.RedirectStandardOutput = true;
   p.StartInfo.RedirectStandardError = true;
   p.StartInfo.CreateNoWindow = true;
   p.Start();
   string szCommandOutput = p.StandardOutput.ReadToEnd();
   p.WaitForExit();

   if (szCommandOutput.ToUpper().IndexOf("REPLY FROM") > -1)
   {
    bPingWorked = true;
   }
  }
  catch(ThreadAbortException)
  {
   //No need to do anything!
  }
  catch(Exception e) 
  {
   //LogStatus.WriteErrorLog(e,"Error","PingHost");
  }
  return bPingWorked;
 }
}
}

From the Client you would call

PingHost = new Ping();
PingHost.OnPingFailed += new Ping.PingFailedHandler(PingHost_OnPingFailed);
PingHost.OnPingReceived +=new Ping.PingReceivedHandler(PingHost_OnPingReceived);
PingHost.Host = *IP you wish to ping*;
PingHost.StartPinging();

Then you would code up methods to capture the PingHost's events defined above

private void PingHost_OnPingReceived(object DataObj, PingReceivedArgs PingReceived)
{
    try
    {
        // code to do something when a successful ping occurrs
    }
    catch (Exception ex) 
    {
       // code to do something when an exception occurrs
    }
 }

private void PingHost_OnPingFailed(object DataObj, PingFailedArgs PingFailed)
{
    try
    {
            // code to do something when a ping failure occurrs
    }
    catch (Exception ex) 
    {
            // code to do something when an exception occurrs
    }
 }
Ron Skufca
Wow! Excelenct, thank you very much. I'll look into this over the next few days.
G-