简单的网络状态监视器示例






4.90/5 (15投票s)
展示如何实现一个在网络接口发生变化时生成事件的系统。
引言
我很失望地发现 .NET Framework 中没有任何东西在网络接口变得活动或不活动时生成事件。 如果您正在编写需要活动网络连接的程序,能够响应可用网络的更改会非常有用。
背景
.NET Framework 确实提供了关于连接到系统的网络接口的一些有用信息,位于 System.Net.NetworkInformation
命名空间中。 最值得注意的是 NetworkInterface
类。 这个类包含一个静态方法 GetAllNetworkInterfaces()
,它返回一个 NetworkInterface
对象数组,其中填充了关于您机器上可用网络适配器的信息。
请注意,重复调用 GetAlllNetworkInterfaces()
方法总是返回对相同类的引用。 因此,如果您保留对网络接口的引用,然后调用 GetAllNetworkInterfaces()
并找到相同的适配器,并比较两者的操作状态属性; 即使网络适配器在这两个调用之间已连接或断开连接,操作状态属性也将相同,因为您比较的是同一个对象。
因此,为了能够测试对 GetAllNetworkInterfaces()
方法的两次调用的差异,需要用第一次调用中的属性值填充另一个对象。然后可以将此对象与当前值进行比较,并可以检测到差异。
为了能够在网络接口更改时引发事件,我们需要一个任务,该任务重复记录 GetAllNetworkInterfaces()
的结果,等待定义的时间,然后比较 GetAllNetworkInterfaces()
的当前结果,并引发适当的事件。
使用代码
附带的项目定义了两个重要的类:NetworkStatus
和 NetworkStatusMonitor
。
NetworkStatus
这充当本地机器网络接口状态的记录,即在构造时;它保留自己的 NetworkInterface
类的属性的副本。
它定义了一个内部类,它是网络接口状态的实际记录,并保留这些类的集合。
/// <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; }
}
NetworkStatus
类还实现了一些方法,以将自身与 NetworkStatus
类的另一个实例进行比较。 这些返回 IEnumerable
,网络状态监视器类使用它们来找出哪些接口已更改
/// <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;
}
}
}
NetworkStatusMonitor
类运行一个循环方法(在其自己的线程中,因此它不会阻塞应用程序的其余部分),该方法存储 NetworkStatus
类的新的实例,等待预定义的毫秒数,然后生成 NetworkStatus
类的新实例,并运行比较方法以识别已连接、已断开连接等的任何适配器。
这是监视器任务方法
/// <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);
}
}
}
程序类的主方法显示了如何将其组合在一起并作为控制台应用程序启动,该应用程序在每次网络接口连接或断开连接时写入消息。
历史
V1.0。