.NET 网络监视器
一个简单的网络监视器。
引言
在本文中,我将介绍我的自定义类 NetworkManager
并解释我的设计思路。我还会介绍其他参考资料,即使用 Win32 API InternetGetConnectedState
和 .NET Framework NetworkInterface
,但最终,我将不使用 InternetGetConnectedState
和 NetworkInterface
。
在这里,您将学习这些技术。
背景
我需要在我的项目中监视网络状态。这是为了检查电缆是否接触不良,以及检查网络是否已启用。所以我开发了一个简单的工具来测试。
为什么我需要监视网络状态?因为在我们的产品中,我们遇到了电缆与网卡接触不良的问题。因此,用户要求提供解决方案,我们在团队会议中讨论了这个问题。我们认为我们需要一个完整的解决方案,并且用户可能也会禁用环境中的网络。
Using the Code
我使用单例来管理所有网络信息。现在,调用此代码来初始化和监视
NetworkManager.Instance.StartMonitor();
然后使用 foreach NetworkManager.Instance.Informations.Values
来获取所需的信息
foreach(NetworkInfo info in NetworkManager.Instance.Informations.Values)
{
Console.WriteLine("Device Name:" + info.DeviceName);
Console.WriteLine("Adapter Type:" + info.AdapterType);
Console.WriteLine("MAC Address:" + info.MacAddress);
Console.WriteLine("Connection Name:" + info.ConnectionID);
Console.WriteLine("IP Address:" + info.IP);
Console.WriteLine("Connection Status:" + info.Status.ToString());
}
最后调用此代码来销毁
NetworkManager.Instance.Destory();
关于代码
public enum NetConnectionStatus
{
Disconnected = 0,
Connecting = 1,
Connected = 2,
Disconnecting = 3,
HardwareNotPresent = 4,
HardwareDisabled = 5,
HardwareMalfunction = 6,
MediaDisconnected = 7,
Authenticating = 8,
AuthenticationSucceeded = 9,
AuthenticationFailed = 10,
InvalidAddress = 11,
CredentialsRequired = 12
}
首先,枚举类型 NetConnectionStatus
是来自 Win32NetworkAdapter
类中属性 NetConnectionStatus
的引用。
在我的项目中,我需要这些信息,所以我声明了它。
static readonly NetworkManager m_instance = new NetworkManager();
我对 NetworkManager
使用单例模式,因为我认为这个类将获取网卡信息,并且所有实例将获得相同的信息,所以单例是最好的。
static NetworkManager()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
"SELECT * FROM Win32_NetworkAdapter WHERE NetConnectionID IS NOT NULL");
foreach (ManagementObject mo in searcher.Get())
{
NetworkInfo info = new NetworkInfo();
info.DeviceName = ParseProperty(mo["Description"]);
info.AdapterType = ParseProperty(mo["AdapterType"]);
info.MacAddress = ParseProperty(mo["MACAddress"]);
info.ConnectionID = ParseProperty(mo["NetConnectionID"]);
info.Status = (NetConnectionStatus)Convert.ToInt32(mo["NetConnectionStatus"]);
SetIP(info);
m_Informations.Add(info.ConnectionID, info);
}
}
static void SetIP(NetworkInfo info)
{
ManagementClass objMC =
new ManagementClass("Win32_NetworkAdapterConfiguration");
foreach (ManagementObject mo in objMC.GetInstances())
{
try
{
if (!(bool)mo["ipEnabled"])
continue;
if (mo["MACAddress"].ToString().Equals(info.MacAddress))
{
string[] ip = (string[])mo["IPAddress"];
info.IP = ip[0];
string[] mask = (string[])mo["IPSubnet"];
info.Mask = mask[0];
string[] gateway = (string[])mo["DefaultIPGateway"];
info.DefaultGateway = gateway[0];
break;
}
}
catch (Exception ex)
{
Debug.WriteLine("[SetIP]:" + ex.Message);
}
}
}
ConnectionID
将显示在 Windows 控制台中,所以我使用该属性作为键。
我使用 ManagementObjectSearcher
在 Win32_NetworkAdapter
中获取网卡信息,但 IP、子网和网关在 Win32_NetworkAdapterConfiguration
中可用。
WQL 不能使用 join 表,所以我使用 SetIP
函数,该函数将通过 MACAddress 在 Win32_NetworkAdapterConfiguration
中获取 IP 地址,因为 MACAddress 存在于 Win32_NetworkAdapter
和 Win32_NetworkAdapterConfiguration
中。
执行图像
当我们在控制台中禁用网络时,监视器将获得断开连接状态。
当电缆接触不良时,它会获取该信息。
这是连接成功的时候
关注点
除了 WMI 之外,我还尝试了 InternetGetConnectedState
API 和 NetworkInterface
。
public class WinINET
{
[DllImport("wininet.dll", SetLastError = true)]
public extern static bool InternetGetConnectedState(out int lpdwFlags,
int dwReserved);
[Flags]
public enum ConnectionStates
{
Modem = 0x1,
LAN = 0x2,
Proxy = 0x4,
RasInstalled = 0x10,
Offline = 0x20,
Configured = 0x40,
}
}
static void WinINETAPI()
{
int flags;
bool isConnected = WinINET.InternetGetConnectedState(out flags, 0);
Console.WriteLine(string.Format("Is connected :{0} Flags:{1}", isConnected,
((WinINET.ConnectionStates)flags).ToString()));
}
当我尝试 InternetGetConnectedState
API 时,我发现当我禁用网卡时,该 API 已经返回 true。(我有两张网卡。)
在我的项目中,前端将使用 LAN 获取客户端的数据,但前端也需要通过另一张网卡连接到 WAN。所以我认为这个函数无法帮助我处理所有的网络状态。 如果你想在 .NET 中使用 API,你必须使用 DllImport
来声明该 API。
枚举 ConnectionStates
是一个标志值,将标志转换为 ConnectionStates
,并使用 ToString()
,我们可以获得所需的信息。
例如,当 flags = 0x18 时,转换为 ConnectionStates
并使用 ToString()
将获得 "LAN,RasInstalled" 字符串。
static void NetInfo()
{
foreach (NetworkInterface face in
NetworkInterface.GetAllNetworkInterfaces())
{
Console.WriteLine("=================================================");
Console.WriteLine(face.Id);
Console.WriteLine(face.Name);
Console.WriteLine(face.NetworkInterfaceType.ToString());
Console.WriteLine(face.OperationalStatus.ToString());
Console.WriteLine(face.Speed);
}
}
这是我电脑上的两张网卡。
当我使用此代码来获取网络信息且网络已连接时,它将显示该信息。OperationalStatus
属性将显示出来。当我从网卡上拔下电缆时,它将显示 *Down*。
但我认为完美的解决方案不仅仅是处理网络电缆,所以我尝试在 Windows 控制台中禁用网络。 禁用网络后,我再次运行代码,但它不显示已禁用的网卡的信息。
所以我认为 NetworkInterface
可能不是一个完美的解决方案。
历史
- V1.3:更新了信息和背景。
- V1.2:更新了源代码项目。
- V1.1:添加了更多细节。
- V1.0:添加了网络监视器的代码。