在开发需要网络连接的程序时,能够响应网络变化是非常有用的。本文将介绍如何使用.NET框架中的System.Net.NetworkInformation命名空间来监控网络接口的状态变化,并生成相应的事件。
.NET框架提供了一些有用的信息,这些信息与系统连接的网络接口有关,这些信息可以在System.Net.NetworkInformation命名空间中找到。特别是NetworkInterface类,它包含了一个静态方法GetAllNetworkInterfaces(),该方法返回一个NetworkInterface对象的数组,这些对象包含了有关机器上可用网络适配器的信息。
需要注意的是,重复调用GetAllNetworkInterfaces()方法总是返回相同的类的引用。因此,如果保留了一个网络接口的引用,然后调用GetAllNetworkInterfaces()并找到相同的适配器,然后比较两个操作状态属性;即使网络适配器在两次调用之间已连接或断开,操作状态属性也将是相同的,因为比较的是同一个对象。
为了能够测试两次调用GetAllNetworkInterfaces()方法之间的差异,需要另一个对象来填充第一次调用的属性值。然后可以将这个对象与当前值进行比较,从而检测到差异。
附带的项目定义了两个重要的类:NetworkStatus和NetworkStatusMonitor。
这个类作为本地机器网络接口状态的记录,它在构造时保留了自己的NetworkInterface类属性的副本。它定义了一个内部类,实际上是网络接口状态的记录,并保留了这些类的集合。
public class NiStatusRecord {
public NiStatusRecord(NetworkInterface ni) {
Interface = ni;
OperationalStatus = ni.OperationalStatus;
Type = ni.NetworkInterfaceType;
Speed = ni.Speed;
}
public NetworkInterface Interface { get; set; }
public OperationalStatus OperationalStatus { get; set; }
public NetworkInterfaceType Type { get; set; }
public long Speed { get; set; }
}
NetworkStatus类还实现了一些方法,用于将自己与另一个NetworkStatus类的实例进行比较。这些方法返回IEnumerable,网络状态监控类使用这些IEnumerable来确定哪些接口发生了变化:
public IEnumerable Connected(NetworkStatus lastStatus) {
foreach (var pair in _status) {
if (lastStatus._status.ContainsKey(pair.Key)) {
if (lastStatus._status[pair.Key].OperationalStatus != OperationalStatus.Up && pair.Value.OperationalStatus == OperationalStatus.Up) {
yield return pair.Value.Interface;
} else {
if (pair.Value.OperationalStatus == OperationalStatus.Up) {
yield return pair.Value.Interface;
}
}
}
}
}
NetworkStatusMonitor类运行一个循环方法(在自己的线程中,因此不会阻塞应用程序的其余部分),该方法存储一个新的NetworkStatus类实例,等待预定义的毫秒数,然后生成一个新的NetworkStatus类实例,并运行比较方法以识别任何已连接、断开连接等的适配器。
private void MonitorTask() {
while (_run) {
try {
if (_last == null) {
_last = new NetworkStatus();
Thread.Sleep(_waitInterval);
continue;
} else {
NetworkStatus current = new NetworkStatus();
if (NetworkInterfaceConnected != null && _monitorNewConnections) {
foreach (var ni in current.Connected(_last)) {
NetworkInterfaceConnected(this, new StatusMonitorEventArgs() {
EventType = StatusMonitorEventType.Connected,
Interface = ni,
LastOperationalStatus = lastStatus
});
}
}
if (NetworkInterfaceDisconnected != null && _monitorDisconnections) {
foreach (var ni in current.Disconnected(_last)) {
NetworkInterfaceDisconnected(this, new StatusMonitorEventArgs() {
EventType = StatusMonitorEventType.Disconnected,
Interface = ni,
LastOperationalStatus = OperationalStatus.Up
});
}
}
if (NetworkInterfaceChanged != null && _monitorAnyStatusChange) {
foreach (var ni in current.Changed(_last)) {
NetworkInterfaceChanged(this, new StatusMonitorEventArgs() {
EventType = StatusMonitorEventType.Changed,
Interface = ni,
LastOperationalStatus = lastStatus
});
}
}
_last = current;
if (_run) Thread.Sleep(_waitInterval);
}
lock (_pulse) Monitor.PulseAll(_pulse);
} catch (Exception exception) {
Console.WriteLine(exception.ToString());
Interlocked.Increment(ref _exceptionCount);
}
}
}