【问题标题】:NetworkInterface.NetworkInterfaceType determines Wireless interface as Ethernet type in Windows 8NetworkInterface.NetworkInterfaceType 将无线接口确定为 Windows 8 中的以太网类型
【发布时间】:2013-02-15 21:10:24
【问题描述】:

我有以下代码用于确定本地机器上无线接口的 IPv4

private List<IPAddressInformation> GetWifiIPAddresses()
{
    var list = new List<IPAddressInformation>();
    var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();

    foreach (var networkInterface in networkInterfaces)
    {
        if (networkInterface.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)
        {
            var interfaceAddressList = networkInterface.GetIPProperties().UnicastAddresses;
            list.AddRange(interfaceAddressList.Where(interfaceIp => interfaceIp.Address.AddressFamily == AddressFamily.InterNetwork));
        }
    }

    return list;
}

在 Windows 7 中,一切都像一个魅力,但在 Windows 8 中,我的 WLAN 接口被确定为以太网适配器。 (NetworkInterfaceType == NetworkInterfaceType.Ethernet 而不是 NetworkInterfaceType.Wireless80211)

这是我的 WLAN 的 ipconfig 屏幕

但它是无线适配器,在 Windows 7 中 ipconfig 将其显示为无线接口。

关于如何解决它的任何线索?是驱动程序问题还是 Windows 8 规格问题? 我还能如何确定本地机器上的 WLAN IP 地址?

谢谢!

编辑

这是因为 Hyper-V 虚拟交换机。 Hyper-V 虚拟交换机覆盖了真实的物理适配器,因此 .NET 无法将其确定为 WiFi 适配器。

当我将“Hyper-V 虚拟交换机管理器”中的开关从我的物理无线适配器移除到 vEthernet 时,它可以像在 Windows 7 中一样正常工作。

但是,转换后的虚拟交换机可能是为实际物理设备确定正确 IP 的大问题。

【问题讨论】:

    标签: c#-4.0 networking ip ip-address wifi


    【解决方案1】:

    切换开关在某种程度上相当于修改物理 LAN 上的网络基础设施……这是程序通常无法控制的。

    机器将具有一个或多个网络适配器,因此它们在不同的操作时间可能具有不同的地址。如果您的问题是关于识别机器的 IP 地址,您可能需要重新构建它。为什么需要 IP 地址?这可能会提出解决问题的其他方法(包括对适配器名称使用启发式方法,而不是依赖适配器类型)。

    如果您需要考虑单个 IP 地址,也许您最好确定用于访问特定服务器的适配器并使用其 IP 地址。 Win32 API GetBestRoute() 为您提供。

    【讨论】:

    • 我有 WP7 应用程序,可以将文件发送到 PC,在客户端我需要向用户显示他的 WiFi IP 地址,以便他可以与手机建立连接并通过 WiFi 传输所需的文件。
    【解决方案2】:

    这完全有可能!

    昨天遇到完全相同的问题并成功解决。

    基本上我们得到了另一种接口类型,因为 Hyper-V 在创建虚拟交换机时做了一些桥接工作。这就是为什么当迭代NetworkInterface.GetAllNetworkInterfaces()时根本没有wlan接口,而具有相同IP地址的新接口是一个虚拟接口,它也参与了带有无线适配器的网桥。

    所以我们需要做到以下几点:

    1. 确定实际的硬件接口
    2. 确定其实际类型

    确定实际的硬件接口

    Windows 中的网络接口以类似堆栈的方式组织。也就是说,一些接口可能位于其他接口之上,并且可能实际的硬件接口将位于这些东西的底部。

    堆栈本身由一个记录数组表示,例如

    [StructLayout(LayoutKind.Sequential)]
    public struct MIB_IFSTACK_ROW
    {
        public uint HigherLayerInterfaceIndex;
        public uint LowerLayerInterfaceIndex;
    }
    

    其中HigherLayerInterfaceIndex 严格高于LowerLayerInterfaceIndex。 有了这些信息和源接口索引就可以很容易地确定实际的硬件接口索引:

    1. 将当前索引设置为源接口索引
    2. 虽然有一条 HigherLayerInterfaceIndex 等于当前索引的记录 - 将当前索引设置为该记录的 LowerLayerInterfaceIndex 并再次重复
    3. 如果没有HigherLayerInterfaceIndex 等于当前索引的记录 - 当前索引就是结果

    使用 WinAPI 方法GetIfStackTable 来检索网络接口堆栈信息。以下 P/Invoke 定义可能会有所帮助:

    [StructLayout(LayoutKind.Sequential)]
    public struct MIB_IFSTACK_ROW
    {
        public uint HigherLayerInterfaceIndex;
        public uint LowerLayerInterfaceIndex;
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct MIB_IFSTACK_TABLE
    {
        public uint NumEntries;
        public MIB_IFSTACK_ROW Table;
    }
    
    [DllImport("iphlpapi.dll", CallingConvention = CallingConvention.StdCall)]
    public static extern Win32Error GetIfStackTable(out IntPtr table);
    
    [DllImport("iphlpapi.dll", CallingConvention = CallingConvention.StdCall)]
    public static extern void FreeMibTable(IntPtr memory);
    

    由于(显然)记录计数可能因调用而异,因此必须首先从 IntPtr 读取计数 (uint32),然后逐个记录编组。下面的代码应该有助于理解这个想法(尽管由于我们内部的东西它不会编译):

    public static IEnumerable<MIB_IFSTACK_ROW> EnumIfStackTable()
    {
        var error = GetIfStackTable(out var table);
        error.ToHRESULT().ThrowIfFailed();
    
        Contract.Assert(table != null);
        Contract.Assert(!table.IsInvalid);
    
        using (table)
        {
            var pointer = table.DangerousGetHandle();
            var entries = (uint)Marshal.ReadInt32(pointer);
            var rowPointer = IntPtr.Add(pointer, IfStackTableOffset);
    
            for (var i = 0; i < entries; i++)
            {
                yield return (MIB_IFSTACK_ROW)Marshal.PtrToStructure(rowPointer, typeof(MIB_IFSTACK_ROW));
                rowPointer = IntPtr.Add(rowPointer, IfStackRowSize);
            }
        }
    }
    

    表格偏移量和行大小是这样计算的:

    internal static readonly int IfStackRowSize = Marshal.SizeOf(typeof(MIB_IFSTACK_ROW));
    internal static readonly int IfStackTableOffset = (int)Marshal.OffsetOf(typeof(MIB_IFSTACK_TABLE), nameof(MIB_IFSTACK_TABLE.Table));
    

    当您完成接口堆栈时,不要忘记调用FreeMibTable

    确定硬件接口类型

    有几个地方我们可以尝试找到具有索引的接口类型,但最可靠的方法是直接从 WinAPI 获取此信息。我建议使用GetIfTable2 WinAPI 函数——它允许我们枚举系统中存在的每个网络接口,并检查它的属性。不幸的是,这次 P/Invoke 对于这个答案来说太大了,但主要思想(和编组)与上一段中的相同。

    拥有MIB_IF_ROW2 结构的数组,可以通过迭代此类数组并将InterfaceIndex 属性与所需的接口索引进行比较,轻松找到所需的接口。找到接口后 - 只需将 Type 属性值转换为 NetworkInterfaceType - 就是这样,你太棒了!

    为什么不使用其他方法:

    1. NetworkInterface.GetAllNetworkInterfaces() 可能不会返回我们想要的接口
    2. WMI Win32_NetworkAdapter - 可能仍显示错误类型
    3. WMI MSFT_NetAdapter - 显示正确的适配器类型,但至少需要 Windows 8

    有用的链接

    【讨论】:

      猜你喜欢
      • 2014-03-07
      • 1970-01-01
      • 2017-02-16
      • 2019-07-11
      • 1970-01-01
      • 2017-07-31
      • 2014-11-21
      • 2023-03-13
      • 1970-01-01
      相关资源
      最近更新 更多