【问题标题】:Reliable method to get machine's MAC address in C#在C#中获取机器MAC地址的可靠方法
【发布时间】:2010-10-25 10:32:03
【问题描述】:

我需要一种方法来使用 C# 获取机器的 MAC 地址,而不管它运行的是什么操作系统。

该应用程序需要在 XP/Vista/Win7 32 位和 64 位以及这些操作系统上运行,但默认为外语。此外,许多 C# 命令和操作系统查询并不适用于所有操作系统。

你有什么想法吗?

我一直在抓取ipconfig /all 的输出,但这非常不可靠,因为每台机器的输出格式都不同。

【问题讨论】:

  • 当您说跨操作系统时,您的意思是跨不同的 Microsoft 操作系统?

标签: c# mac-address


【解决方案1】:

更清洁的解决方案

var macAddr = 
    (
        from nic in NetworkInterface.GetAllNetworkInterfaces()
        where nic.OperationalStatus == OperationalStatus.Up
        select nic.GetPhysicalAddress().ToString()
    ).FirstOrDefault();

或者:

String firstMacAddress = NetworkInterface
    .GetAllNetworkInterfaces()
    .Where( nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback )
    .Select( nic => nic.GetPhysicalAddress().ToString() )
    .FirstOrDefault();

【讨论】:

  • 或者 lambda,如果那是你的事! return NetworkInterface.GetAllNetworkInterfaces().Where(nic => nic.OperationalStatus == OperationalStatus.Up).Select(nic => nic.GetPhysicalAddress().ToString()).FirstOrDefault();(如果不是你的东西,它应该是你的东西。)
  • 获得最快的简洁方法:var networks = NetworkInterface.GetAllNetworkInterfaces(); var activeNetworks = networks.Where(ni => ni.OperationalStatus == OperationalStatus.Up && ni.NetworkInterfaceType != NetworkInterfaceType.Loopback); var sortedNetworks = activeNetworks.OrderByDescending(ni => ni.Speed); return sortedNetworks.First().GetPhysicalAddress().ToString();
  • 首先选择并不总是最好的选择。选择最常用的连接:stackoverflow.com/a/51821927/3667
  • 优化说明:你可以在最后的Select之前调用FirstOrDefault。这样,它只会获取物理地址并将其序列化为您获得的实际NetworkInterface。不要忘记在 FirstOrDefault 之后添加空检查 (?)。
  • 一种计算速度更快的方法,您不需要评估所有符合给定条件的网络,您只需要其中的第一个:NetworkInterface .GetAllNetworkInterfaces() .FirstOrDefault(nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback)? .GetPhysicalAddress().ToString();
【解决方案2】:

这是一些 C# 代码,它返回第一个可操作网络接口的 MAC 地址。假设 NetworkInterface 程序集是在其他操作系统上使用的运行时(即 Mono)中实现的,那么这将适用于其他操作系统。

新版本:返回速度最快且 MAC 地址有效的网卡。

/// <summary>
/// Finds the MAC address of the NIC with maximum speed.
/// </summary>
/// <returns>The MAC address.</returns>
private string GetMacAddress()
{
    const int MIN_MAC_ADDR_LENGTH = 12;
    string macAddress = string.Empty;
    long maxSpeed = -1;

    foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
    {
        log.Debug(
            "Found MAC Address: " + nic.GetPhysicalAddress() +
            " Type: " + nic.NetworkInterfaceType);

        string tempMac = nic.GetPhysicalAddress().ToString();
        if (nic.Speed > maxSpeed &&
            !string.IsNullOrEmpty(tempMac) &&
            tempMac.Length >= MIN_MAC_ADDR_LENGTH)
        {
            log.Debug("New Max Speed = " + nic.Speed + ", MAC: " + tempMac);
            maxSpeed = nic.Speed;
            macAddress = tempMac;
        }
    }

    return macAddress;
}

原始版本:只返回第一个。

/// <summary>
/// Finds the MAC address of the first operation NIC found.
/// </summary>
/// <returns>The MAC address.</returns>
private string GetMacAddress()
{
    string macAddresses = string.Empty;

    foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
    {
        if (nic.OperationalStatus == OperationalStatus.Up)
        {
            macAddresses += nic.GetPhysicalAddress().ToString();
            break;
        }
    }

    return macAddresses;
}

我不喜欢这种方法的唯一一点是,如果您有 Nortel Packet Miniport 或某种类型的 VPN 连接,它就有可能被选中。据我所知,没有办法将实际物理设备的 MAC 与某种类型的虚拟网络接口区分开来。

【讨论】:

  • 不要只选择第一个操作界面。这可能会返回 Loopback 接口、偶尔连接的 3G 卡等,这些可能不是您想要的。 NetworkInterfaceType (msdn.microsoft.com/en-us/library/…) 将为您提供有关 NetworkInterface 连接的更多信息,以便您做出更明智的选择。还要记住,一台机器上可能有许多活动连接,它们的顺序可能无法预测。
  • @DaveR。我查看了 NetworkInterfaceType,它基本上几乎总是返回以太网,即使根据我的经验它是一个虚拟适配器,所以我发现它非常没用。
  • 您应该选择具有最低 GatewayMetric 的接口。这应该是具有“最快、最可靠或资源最少的路线”的连接。基本上,它将为您提供 Windows 喜欢使用的界面。但是,我认为您需要 WMI 才能真正做到这一点。我会看看我能不能让它工作......
  • 为了完整起见,使用using System.Net.NetworkInformation;访问NetworkInterface类
  • FWIW,如果您安装了千兆网卡和 Hyper-V,您还将拥有一个 10 吉比特的虚拟网卡。 :) 难以解决的问题...
【解决方案3】:

Win32_NetworkAdapterConfiguration WMI classMACAddress 属性可以为您提供适配器的 MAC 地址。 (System.Management 命名空间)

MACAddress

    Data type: string
    Access type: Read-only

    Media Access Control (MAC) address of the network adapter. A MAC address is assigned by the manufacturer to uniquely identify the network adapter.

    Example: "00:80:C7:8F:6C:96"

如果您不熟悉 WMI API(Windows 管理规范),有一个适用于 .NET 应用程序的 good overview here

WMI 可用于具有 .Net 运行时的所有 Windows 版本。

这是一个代码示例:

System.Management.ManagementClass mc = default(System.Management.ManagementClass);
ManagementObject mo = default(ManagementObject);
mc = new ManagementClass("Win32_NetworkAdapterConfiguration");

ManagementObjectCollection moc = mc.GetInstances();
    foreach (var mo in moc) {
        if (mo.Item("IPEnabled") == true) {
              Adapter.Items.Add("MAC " + mo.Item("MacAddress").ToString());
         }
     }

【讨论】:

    【解决方案4】:

    如果您要连接的机器是 Windows 机器,WMI 是最好的解决方案,但如果您正在查看 linux、mac 或其他类型的网络适配器,那么您将需要使用其他东西。以下是一些选项:

    1. 使用 DOS 命令 nbtstat -a 。创建一个进程,调用这个命令,解析输出。
    2. 首先 Ping IP 以确保您的 NIC 将命令缓存在其 ARP 表中,然后使用 DOS 命令 arp -a 。像选项 1 一样解析过程的输出。
    3. 在 iphlpapi.dll 中对 sendarp 使用可怕的非托管调用

    这是第 3 项的示例。如果 WMI 不是可行的解决方案,这似乎是最佳选择:

    using System.Runtime.InteropServices;
    ...
    [DllImport("iphlpapi.dll", ExactSpelling = true)]
            public static extern int SendARP(int DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen);
    ...
    private string GetMacUsingARP(string IPAddr)
    {
        IPAddress IP = IPAddress.Parse(IPAddr);
        byte[] macAddr = new byte[6];
        uint macAddrLen = (uint)macAddr.Length;
    
        if (SendARP((int)IP.Address, 0, macAddr, ref macAddrLen) != 0)
            throw new Exception("ARP command failed");
    
        string[] str = new string[(int)macAddrLen];
        for (int i = 0; i < macAddrLen; i++)
            str[i] = macAddr[i].ToString("x2");
    
        return string.Join(":", str);
    }
    

    为了给予应得的荣誉,这是该代码的基础: http://www.pinvoke.net/default.aspx/iphlpapi.sendarp#

    【讨论】:

    • 我正在寻找与 OP 相同的东西,而这正是我需要的东西!
    • 在选项 1 和 2 中,如果您在 Windows 机器上,您的意思是 DOS 命令,在 Linux 或 Mac 上是等效命令,对吧?
    【解决方案5】:

    恕我直言,返回第一个 mac 地址并不是一个好主意,尤其是在托管虚拟机时。因此我检查发送/接收字节总和并选择最常用的连接,这并不完美,但应该是正确的 9/10 次。

    public string GetDefaultMacAddress()
    {
        Dictionary<string, long> macAddresses = new Dictionary<string, long>();
        foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
        {
            if (nic.OperationalStatus == OperationalStatus.Up)
                macAddresses[nic.GetPhysicalAddress().ToString()] = nic.GetIPStatistics().BytesSent + nic.GetIPStatistics().BytesReceived;
        }
        long maxValue = 0;
        string mac = "";
        foreach(KeyValuePair<string, long> pair in macAddresses)
        {
            if (pair.Value > maxValue)
            {
                mac = pair.Key;
                maxValue = pair.Value;
            }
        }
        return mac;
    }
    

    【讨论】:

      【解决方案6】:

      我们使用 WMI 来获取具有最低 metric 的接口的 mac 地址,例如界面窗口会更喜欢使用,如下所示:

      public static string GetMACAddress()
      {
          ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true");
          IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>();
          string mac = (from o in objects orderby o["IPConnectionMetric"] select o["MACAddress"].ToString()).FirstOrDefault();
          return mac;
      }
      

      或在 Silverlight 中(需要提升信任):

      public static string GetMACAddress()
      {
          string mac = null;
          if ((Application.Current.IsRunningOutOfBrowser) && (Application.Current.HasElevatedPermissions) && (AutomationFactory.IsAvailable))
          {
              dynamic sWbemLocator = AutomationFactory.CreateObject("WbemScripting.SWBemLocator");
              dynamic sWbemServices = sWbemLocator.ConnectServer(".");
              sWbemServices.Security_.ImpersonationLevel = 3; //impersonate
      
              string query = "SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true";
              dynamic results = sWbemServices.ExecQuery(query);
      
              int mtu = int.MaxValue;
              foreach (dynamic result in results)
              {
                  if (result.IPConnectionMetric < mtu)
                  {
                      mtu = result.IPConnectionMetric;
                      mac = result.MACAddress;
                  }
              }
          }
          return mac;
      }
      

      【讨论】:

        【解决方案7】:

        此方法将确定用于连接到指定 url 和端口的网络接口的 MAC 地址。

        这里所有的答案都不能达到这个目标。

        我多年前(2014 年)写了这个答案。所以我决定给它一点“整容”。请查看更新部分

            /// <summary>
            /// Get the MAC of the Netowrk Interface used to connect to the specified url.
            /// </summary>
            /// <param name="allowedURL">URL to connect to.</param>
            /// <param name="port">The port to use. Default is 80.</param>
            /// <returns></returns>
            private static PhysicalAddress GetCurrentMAC(string allowedURL, int port = 80)
            {
                //create tcp client
                var client = new TcpClient();
        
                //start connection
                client.Client.Connect(new IPEndPoint(Dns.GetHostAddresses(allowedURL)[0], port));
        
                //wai while connection is established
                while(!client.Connected)
                {
                    Thread.Sleep(500);
                }
        
                //get the ip address from the connected endpoint
                var ipAddress = ((IPEndPoint)client.Client.LocalEndPoint).Address;
        
                //if the ip is ipv4 mapped to ipv6 then convert to ipv4
                if(ipAddress.IsIPv4MappedToIPv6)
                    ipAddress = ipAddress.MapToIPv4();        
        
                Debug.WriteLine(ipAddress);
        
                //disconnect the client and free the socket
                client.Client.Disconnect(false);
                
                //this will dispose the client and close the connection if needed
                client.Close();
        
                var allNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
        
                //return early if no network interfaces found
                if(!(allNetworkInterfaces?.Length > 0))
                    return null;
        
                foreach(var networkInterface in allNetworkInterfaces)
                {
                    //get the unicast address of the network interface
                    var unicastAddresses = networkInterface.GetIPProperties().UnicastAddresses;
                   
                    //skip if no unicast address found
                    if(!(unicastAddresses?.Count > 0))
                        continue;
        
                    //compare the unicast addresses to see 
                    //if any match the ip address used to connect over the network
                    for(var i = 0; i < unicastAddresses.Count; i++)
                    {
                        var unicastAddress = unicastAddresses[i];
        
                        //this is unlikely but if it is null just skip
                        if(unicastAddress.Address == null)
                            continue;
                        
                        var ipAddressToCompare = unicastAddress.Address;
        
                        Debug.WriteLine(ipAddressToCompare);
        
                        //if the ip is ipv4 mapped to ipv6 then convert to ipv4
                        if(ipAddressToCompare.IsIPv4MappedToIPv6)
                            ipAddressToCompare = ipAddressToCompare.MapToIPv4();
        
                        Debug.WriteLine(ipAddressToCompare);
        
                        //skip if the ip does not match
                        if(!ipAddressToCompare.Equals(ipAddress))
                            continue;
        
                        //return the mac address if the ip matches
                        return networkInterface.GetPhysicalAddress();
                    }
                      
                }
        
                //not found so return null
                return null;
            }
        

        要调用它,您需要传递一个 URL 来连接,如下所示:

        var mac = GetCurrentMAC("www.google.com");
        

        您还可以指定端口号。如果未指定,默认为 80。

        更新:

        2020

        • 添加了 cmets 来解释代码。
        • 已更正以与较新版本一起使用 使用 IPV4 映射到 IPV6 的操作系统(如 windows 10)。
        • 减少嵌套。
        • 升级代码使用“var”。

        【讨论】:

        • 这很有趣,我会尝试一下,因为在我的情况下,我希望客户端发现 a) 用于与我的服务器通信的源地址(它不一定是通过互联网) 和 b) 提供此 IP 地址的 NIC 的 MAC 地址是什么...
        【解决方案8】:
        public static PhysicalAddress GetMacAddress()
        {
            var myInterfaceAddress = NetworkInterface.GetAllNetworkInterfaces()
                .Where(n => n.OperationalStatus == OperationalStatus.Up && n.NetworkInterfaceType != NetworkInterfaceType.Loopback)
                .OrderByDescending(n => n.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
                .Select(n => n.GetPhysicalAddress())
                .FirstOrDefault();
        
            return myInterfaceAddress;
        }
        

        【讨论】:

        • 如果我运行这段代码,它会得到运行应用程序的人的地址吗?这意味着它不会获得托管它的服务器 IP 地址,对吗?
        • 它获取主机,服务器的MAC地址。
        【解决方案9】:

        您可以选择 NIC ID:

         foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) {
             if (nic.OperationalStatus == OperationalStatus.Up){
                 if (nic.Id == "yay!")
             }
         }
        

        这不是 MAC 地址,而是一个唯一标识符,如果这正是您要查找的内容。

        【讨论】:

          【解决方案10】:

          我真的很喜欢 AVee 的 IP 连接指标最低的解决方案!但是,如果安装了具有相同指标的第二个网卡,则 MAC 比较可能会失败...

          最好将接口的描述与 MAC 一起存储。在以后的比较中,您可以通过此字符串识别正确的 nic。这是一个示例代码:

             public static string GetMacAndDescription()
              {
                  ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true");
                  IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>();
                  string mac = (from o in objects orderby o["IPConnectionMetric"] select o["MACAddress"].ToString()).FirstOrDefault();
                  string description = (from o in objects orderby o["IPConnectionMetric"] select o["Description"].ToString()).FirstOrDefault();
                  return mac + ";" + description;
              }
          
              public static string GetMacByDescription( string description)
              {
                  ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true");
                  IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>();
                  string mac = (from o in objects where o["Description"].ToString() == description select o["MACAddress"].ToString()).FirstOrDefault();
                  return mac;
              }
          

          【讨论】:

            【解决方案11】:

            假设我有一个使用本地 IP 192.168.0.182 的 TcpConnection。然后如果我想知道那个网卡的mac地址,我会调用这个方法:GetMacAddressUsedByIp("192.168.0.182")

            public static string GetMacAddressUsedByIp(string ipAddress)
                {
                    var ips = new List<string>();
                    string output;
            
                    try
                    {
                        // Start the child process.
                        Process p = new Process();
                        // Redirect the output stream of the child process.
                        p.StartInfo.UseShellExecute = false;
            
                        p.StartInfo.RedirectStandardOutput = true;
                        p.StartInfo.UseShellExecute = false;
                        p.StartInfo.CreateNoWindow = true;
                        p.StartInfo.FileName = "ipconfig";
                        p.StartInfo.Arguments = "/all";
                        p.Start();
                        // Do not wait for the child process to exit before
                        // reading to the end of its redirected stream.
                        // p.WaitForExit();
                        // Read the output stream first and then wait.
                        output = p.StandardOutput.ReadToEnd();
                        p.WaitForExit();
            
                    }
                    catch
                    {
                        return null;
                    }
            
                    // pattern to get all connections
                    var pattern = @"(?xis) 
            (?<Header>
                 (\r|\n) [^\r]+ :  \r\n\r\n
            )
            (?<content>
                .+? (?= ( (\r\n\r\n)|($)) )
            )";
            
                    List<Match> matches = new List<Match>();
            
                    foreach (Match m in Regex.Matches(output, pattern))
                        matches.Add(m);
            
                    var connection = matches.Select(m => new
                    {
                        containsIp = m.Value.Contains(ipAddress),
                        containsPhysicalAddress = Regex.Match(m.Value, @"(?ix)Physical \s Address").Success,
                        content = m.Value
                    }).Where(x => x.containsIp && x.containsPhysicalAddress)
                    .Select(m => Regex.Match(m.content, @"(?ix)  Physical \s address [^:]+ : \s* (?<Mac>[^\s]+)").Groups["Mac"].Value).FirstOrDefault();
            
                    return connection;
                }
            

            【讨论】:

            • 这效率不高...我不建议这样做。
            【解决方案12】:

            真的不想挖掘这篇旧帖子,但我觉得这个问题值得另一个特定于 Windows 8-10 的答案。

            使用Windows.Networking.Connectivity命名空间中的NetworkInformation,您可以获得windows正在使用的网络适配器的ID。然后就可以通过前面提到的GetAllNetworkInterfaces()获取接口MAC地址了。

            这在 Windows 应用商店应用中不起作用,因为 System.Net.NetworkInformation 中的 NetworkInterface 不会公开 GetAllNetworkInterfaces。

            string GetMacAddress()
            {
                var connectionProfile = NetworkInformation.GetInternetConnectionProfile();
                if (connectionProfile == null) return "";
            
                var inUseId = connectionProfile.NetworkAdapter.NetworkAdapterId.ToString("B").ToUpperInvariant();
                if(string.IsNullOrWhiteSpace(inUseId)) return "";
            
                var mac = NetworkInterface.GetAllNetworkInterfaces()
                    .Where(n => inUseId == n.Id)
                    .Select(n => n.GetPhysicalAddress().GetAddressBytes().Select(b=>b.ToString("X2")))
                    .Select(macBytes => string.Join(" ", macBytes))
                    .FirstOrDefault();
            
                return mac;
            }
            

            【讨论】:

              【解决方案13】:
              string mac = "";
              foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
                          {
              
                              if (nic.OperationalStatus == OperationalStatus.Up && (!nic.Description.Contains("Virtual") && !nic.Description.Contains("Pseudo")))
                              {
                                  if (nic.GetPhysicalAddress().ToString() != "")
                                  {
                                      mac = nic.GetPhysicalAddress().ToString();
                                  }
                              }
                          }
              MessageBox.Show(mac);
              

              【讨论】:

              • 这个答案可以通过简要说明代码的作用以及它如何解决问题来改进。
              【解决方案14】:

              稍微更改了 blak3r 他的代码。如果您有两个速度相同的适配器。按 MAC 排序,因此您始终得到相同的值。

              public string GetMacAddress()
              {
                  const int MIN_MAC_ADDR_LENGTH = 12;
                  string macAddress = string.Empty;
                  Dictionary<string, long> macPlusSpeed = new Dictionary<string, long>();
                  try
                  {
                      foreach(NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
                      {
                          System.Diagnostics.Debug.WriteLine("Found MAC Address: " + nic.GetPhysicalAddress() + " Type: " + nic.NetworkInterfaceType);
              
                          string tempMac = nic.GetPhysicalAddress().ToString();
              
                          if(!string.IsNullOrEmpty(tempMac) && tempMac.Length >= MIN_MAC_ADDR_LENGTH)
                              macPlusSpeed.Add(tempMac, nic.Speed);
                      }
              
                      macAddress = macPlusSpeed.OrderByDescending(row => row.Value).ThenBy(row => row.Key).FirstOrDefault().Key;
                  }
                  catch{}
              
                  System.Diagnostics.Debug.WriteLine("Fastest MAC address: " + macAddress);
              
                  return macAddress;
              }
              

              【讨论】:

                【解决方案15】:
                foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
                {
                     if (nic.OperationalStatus == OperationalStatus.Up)
                     {
                            PhysicalAddress Mac = nic.GetPhysicalAddress();
                     }
                }
                

                【讨论】:

                  【解决方案16】:

                  ipconfig.exe 是使用各种 DLL 实现的,包括 iphlpapi.dll ... 谷歌搜索 iphlpapi 揭示了 MSDN 中记录的相应 Win32 API。

                  【讨论】:

                    【解决方案17】:

                    试试这个:

                        /// <summary>
                        /// returns the first MAC address from where is executed 
                        /// </summary>
                        /// <param name="flagUpOnly">if sets returns only the nic on Up status</param>
                        /// <returns></returns>
                        public static string[] getOperationalMacAddresses(Boolean flagUpOnly)
                        {
                            string[] macAddresses = new string[NetworkInterface.GetAllNetworkInterfaces().Count()];
                    
                            int i = 0;
                            foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
                            {
                                if (nic.OperationalStatus == OperationalStatus.Up || !flagUpOnly)
                                {
                                    macAddresses[i] += ByteToHex(nic.GetPhysicalAddress().GetAddressBytes());
                                    //break;
                                    i++;
                                }
                            }
                            return macAddresses;
                        }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2011-01-20
                      • 2013-04-23
                      • 1970-01-01
                      • 1970-01-01
                      • 2022-10-14
                      • 1970-01-01
                      • 2012-09-29
                      • 2013-03-24
                      相关资源
                      最近更新 更多