3

我有以下代码用于确定本地机器上无线接口的 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 的大问题。

4

2 回答 2

0

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

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

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

于 2013-03-01T15:34:11.077 回答
0

这是完全可能的!

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

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

所以我们需要做以下事情:

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

确定实际的硬件接口

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

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

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

whereHigherLayerInterfaceIndex严格高于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

有用的链接

于 2020-07-08T11:58:09.970 回答