Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

Simple Network Status Monitor Example

4.90/5 (16 votes)
5 Jun 2011CPOL2 min read 63.5K   2.8K  
Shows how to implement a system to generate events when network interfaces change.

Introduction

I was disappointed to discover nothing in the .NET Framework that generated events when network interfaces became active or inactive. If you are writing a program that requires an active network connection, it can be very useful to be able to respond to changes in the available networks.

ScreenShot600.png

Background

The .NET Framework does give some useful information about the network interfaces connected to the system in the System.Net.NetworkInformation namespace. Most notably, the NetworkInterface class. This class contains a static method GetAllNetworkInterfaces(), that returns an array of NetworkInterface objects, populated with information about the available network adapters on your machine.

Note that repeated calls to the GetAlllNetworkInterfaces() method always returns references to the same classes. Thus if you keep a reference to a network interface, then call GetAllNetworkInterfaces() and find the same adapter, and compare the operational-status properties of the two; even if the network adapter connected or disconnected between the two calls, the operational status properties will be identical, because you are comparing the same object.

So to be able to test the difference between two calls to the GetAllNetworkInterfaces() method, another object will need to be populated with the values of the properties from the first call. This object can then be compared to the current values and a difference can be detected. 

To be able to raise events when a network interface changes, we need a task that is repeatedly recording the results of GetAllNetworkInterfaces(), waiting a defined time, then comparing the current results of GetAllNetworkInterfaces(), and raising the appropriate events. 

Using the code

The attached project defines two important classes: NetworkStatus and NetworkStatusMonitor.

NetworkStatus

This serves as a record of the network-interface status(es) for the local machine at the time it was constructed; it keeps its own copies of the NetworkInterface class' properties.

It defines an inner-class that is the actual record of a network interface status, and keeps a collection of these classes.

C#
/// <summary>
/// keeps a record of a network interface status.
/// </summary>
public class NiStatusRecord
{
    /// <summary>
    /// construct the network interface status record.
    /// </summary>
    /// <param name="ni"></param>
    public NiStatusRecord(NetworkInterface ni)
    {
        Interface = ni;
        OperationalStatus = ni.OperationalStatus;
        Type = ni.NetworkInterfaceType;
        Speed = ni.Speed;
    }

    /// <summary>
    /// the network interface
    /// </summary>
    public NetworkInterface Interface { get; set; }

    /// <summary>
    /// the recorded operational status of the network interface
    /// at the time this class was constructed.
    /// </summary>
    public OperationalStatus OperationalStatus { get; set; }

    /// <summary>
    /// the recorded type of the network interface
    /// at the tine this class was constructed.
    /// </summary>
    public NetworkInterfaceType Type { get; set; }

    /// <summary>
    /// the recorded speed of the network interface
    /// at the time this class was constructed.
    /// </summary>
    public long Speed { get; set; }
}

The NetworkStatus class also implements a number of methods to compare itself against another instance of the NetworkStatus class. These return IEnumerables that the network status monitor class uses to figure out which interfaces have changed:

C#
/// <summary>
/// get an enumerable of network interfaces that have connected
/// since the last status. this includes "UP" adapters that
/// were not present in the last test.
/// </summary>
/// <param name="lastStatus">the last NetworkStatus test results.</param>
/// <returns>
/// an enumerable of the newly connected NetworkInterface objects
/// </returns>
public IEnumerable<NetworkInterface> Connected(NetworkStatus lastStatus)
{
    // enumerate the current list of interfaces:
    foreach (var pair in _status)
    {
        // determine if the interface was in the last snapshot:
        if (lastStatus._status.ContainsKey(pair.Key))
        {
            // if the current status is "Up" and the last
            // status wasn't, the interface has connected.
            if (lastStatus._status[pair.Key].OperationalStatus != OperationalStatus.Up &&
                pair.Value.OperationalStatus == OperationalStatus.Up)
                yield return pair.Value.Interface;
        }
        else
        {
            // if the interface was not in the last snapshot,
            // and is "up" then it has connected.
            if (pair.Value.OperationalStatus == OperationalStatus.Up)
                yield return pair.Value.Interface;
        }
    }
}

The NetworkStatusMonitor class runs a looping method (in its own thread so it doesn't block the rest of the application) that stores a new instance of the NetworkStatus  class, waits a predefined number of milliseconds, then generates a new instance of the NetworkStatus class, and runs the comparison methods to identify any adapters that have connected, disconnected etc.

This is the monitor-task method:

C#
/// <summary>
/// the task given to the monitor thread.
/// </summary>
private void MonitorTask()
{
    // loop while the run flag is true.
    while (_run)
    {
        try
        {
            // has the last status been taken?
            if (_last == null)
            {
                // snapshot the current status.
                _last = new NetworkStatus();

                // sleep for the duration of the poll interval.
                Thread.Sleep(_waitInterval);

                // run to the next iteration.
                continue;
            }
            else
            {
                // get the current network status:
                NetworkStatus current = new NetworkStatus();

                // test for changes and raise events where neccessary.
                if (NetworkInterfaceConnected != null && _monitorNewConnections)
                {
                    // evaluate all the network interfaces that have connected since the
                    // last snapshot
                    foreach (var ni in current.Connected(_last))
                    {
                        // test if the network interface was in the last snapshot:
                        OperationalStatus lastStatus = OperationalStatus.NotPresent;
                        if (_last.Contains(ni.Id))
                            lastStatus = _last[ni.Id].OperationalStatus;

                        // raise the interface connected event:
                        NetworkInterfaceConnected(this, new StatusMonitorEventArgs()
                        {
                            EventType = StatusMonitorEventType.Connected,
                            Interface = ni,
                            LastOperationalStatus = lastStatus
                        });
                    }
                }

                // test for interface dis-connections
                if (NetworkInterfaceDisconnected != null && _monitorDisconnections)
                {
                    // enumerate the network interfaces that were Up but are not now.
                    foreach (var ni in current.Disconnected(_last))
                    {
                        // raise the interface dis-connected event:
                        NetworkInterfaceDisconnected(this, new StatusMonitorEventArgs()
                        {
                            // set the event-type, interface and last status.
                            EventType = StatusMonitorEventType.Disconnected,
                            Interface = ni,
                            LastOperationalStatus = OperationalStatus.Up
                        });
                    }
                }

                // test for interface changes.
                if (NetworkInterfaceChanged != null && _monitorAnyStatusChange)
                {
                    // enumerate the interfaces that have changed status in any way since 
                    // the last snapshot.
                    foreach (var ni in current.Changed(_last))
                    {
                        // find the last status of the interface:
                        OperationalStatus lastStatus = OperationalStatus.NotPresent;
                        if (_last.Contains(ni.Id))
                            lastStatus = _last[ni.Id].OperationalStatus;

                        // raise the interface changed event:
                        NetworkInterfaceChanged(this, new StatusMonitorEventArgs()
                        {
                            // set the event-type interface and last status.
                            EventType = StatusMonitorEventType.Changed,
                            Interface = ni,
                            LastOperationalStatus = lastStatus
                        });
                    }
                }

                // set last to the current.
                _last = current;

                // wait...
                if (_run)
                    Thread.Sleep(_waitInterval);
            }

            // pulse any threads waiting in WaitForPoll.
            lock (_pulse)
                Monitor.PulseAll(_pulse);
        }
        catch (Exception exception)
        {
            // handle the exception....(real exception handler should go here)
            Console.WriteLine(exception.ToString());

            // increment the exception counter.
            Interlocked.Increment(ref _exceptionCount);
        }
    }
}

The main method of the program class shows how this is put together and started up as a console application that writes messages each time a network interface connects or disconnects.

History

V1.0.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)