65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET 网络监视器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (20投票s)

2011年7月15日

CPOL

3分钟阅读

viewsIcon

124289

downloadIcon

12889

一个简单的网络监视器。

引言

在本文中,我将介绍我的自定义类 NetworkManager 并解释我的设计思路。我还会介绍其他参考资料,即使用 Win32 API InternetGetConnectedState 和 .NET Framework NetworkInterface,但最终,我将不使用 InternetGetConnectedStateNetworkInterface

在这里,您将学习这些技术。

背景

我需要在我的项目中监视网络状态。这是为了检查电缆是否接触不良,以及检查网络是否已启用。所以我开发了一个简单的工具来测试。

为什么我需要监视网络状态?因为在我们的产品中,我们遇到了电缆与网卡接触不良的问题。因此,用户要求提供解决方案,我们在团队会议中讨论了这个问题。我们认为我们需要一个完整的解决方案,并且用户可能也会禁用环境中的网络。

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 控制台中,所以我使用该属性作为键。

我使用 ManagementObjectSearcherWin32_NetworkAdapter 中获取网卡信息,但 IP、子网和网关在 Win32_NetworkAdapterConfiguration 中可用。

WQL 不能使用 join 表,所以我使用 SetIP 函数,该函数将通过 MACAddress 在 Win32_NetworkAdapterConfiguration 中获取 IP 地址,因为 MACAddress 存在于 Win32_NetworkAdapterWin32_NetworkAdapterConfiguration 中。

执行图像

当我们在控制台中禁用网络时,监视器将获得断开连接状态。

11.JPG

当电缆接触不良时,它会获取该信息。

13.JPG

这是连接成功的时候

12.JPG

关注点

除了 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:添加了网络监视器的代码。
© . All rights reserved.