从 C# 中的 IP 获取本地网络上的机器 MAC 地址

Posted

技术标签:

【中文标题】从 C# 中的 IP 获取本地网络上的机器 MAC 地址【英文标题】:Get a machines MAC address on the local network from its IP in C# 【发布时间】:2012-09-29 22:52:17 【问题描述】:

我正在尝试编写一个函数,该函数将单个 IP address 作为参数并在我的本地网络上查询该机器的 MAC address

我已经看到了许多获取本地计算机自己的MAC address 的示例,但是没有一个(我发现)似乎查询本地网络计算机。

我知道这样的任务是可以完成的,因为这个Wake on LAN scanner 软件会扫描本地 IP 范围并返回机器上所有机器的 MAC 地址/主机名。

谁能告诉我从哪里开始尝试编写一个函数来在 C# 中实现这一点?任何帮助,将不胜感激。谢谢

编辑:

根据下面 Marco Mp 的评论,使用了 ARP 表。 arp class

【问题讨论】:

不确定它是否有效,但通过快速谷歌搜索,我发现这个库应该可以解决问题:http://www.tamirgal.com/blog/post/ARP-Resolver-C-Class.aspx 谢谢,我相信我读过 ARP 表不一致,想知道是否有办法“ping”MAC 地址。 认为如果您执行常规 ping(或以其他方式尝试联系)IP 地址,它将导致 ARP 表刷新(否则网络堆栈将无法首先联系机器);当然,这将(如果有的话)只有在所需的机器在线时才有效。我认为离线 IP 地址无法获得可靠的结果,特别是如果您有动态分配的 IP。不过我不是网络专家,所以我可能错了(试图与您一起思考这个问题)。 谢谢,ARP 表是要走的路。第一条评论中的示例有点困难,因此发布了替代方案。干杯 试试这个干净整洁的解决方案:***.com/a/37155004/6229375 【参考方案1】:
public string GetMacAddress(string ipAddress)

    string macAddress = string.Empty;
    System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
    pProcess.StartInfo.FileName = "arp";
    pProcess.StartInfo.Arguments = "-a " + ipAddress;
    pProcess.StartInfo.UseShellExecute = false;
    pProcess.StartInfo.RedirectStandardOutput = true;
      pProcess.StartInfo.CreateNoWindow = true;
    pProcess.Start();
    string strOutput = pProcess.StandardOutput.ReadToEnd();
    string[] substrings = strOutput.Split('-');
    if (substrings.Length >= 8)
    
       macAddress = substrings[3].Substring(Math.Max(0, substrings[3].Length - 2)) 
                + "-" + substrings[4] + "-" + substrings[5] + "-" + substrings[6] 
                + "-" + substrings[7] + "-" 
                + substrings[8].Substring(0, 2);
        return macAddress;
    

    else
    
        return "not found";
    

很晚的编辑: 在开源项目 iSpy (https://github.com/ispysoftware/iSpy) 中,他们使用这个代码,更好一点

  public static void RefreshARP()
        
            _arpList = new Dictionary<string, string>();
            _arpList.Clear();
            try
            
                var arpStream = ExecuteCommandLine("arp", "-a");
                // Consume first three lines
                for (int i = 0; i < 3; i++)
                
                    arpStream.ReadLine();
                
                // Read entries
                while (!arpStream.EndOfStream)
                
                    var line = arpStream.ReadLine();
                    if (line != null)
                    
                        line = line.Trim();
                        while (line.Contains("  "))
                        
                            line = line.Replace("  ", " ");
                        
                        var parts = line.Trim().Split(' ');

                        if (parts.Length == 3)
                        
                            string ip = parts[0];
                            string mac = parts[1];
                            if (!_arpList.ContainsKey(ip))
                                _arpList.Add(ip, mac);
                        
                    
                
            
            catch (Exception ex)
            
                Logger.LogExceptionToFile(ex, "ARP Table");
            
            if (_arpList.Count > 0)
            
                foreach (var nd in List)
                
                    string mac;
                    ARPList.TryGetValue(nd.IPAddress.ToString(), out mac);
                    nd.MAC = mac;    
                
            
        

https://github.com/ispysoftware/iSpy/blob/master/Server/NetworkDeviceList.cs

更新 2 更晚了,但我认为这是最好的,因为它使用的正则表达式可以更好地检查精确匹配。

public string getMacByIp(string ip)

    var macIpPairs = GetAllMacAddressesAndIppairs();
    int index = macIpPairs.FindIndex(x => x.IpAddress == ip);
    if (index >= 0)
    
        return macIpPairs[index].MacAddress.ToUpper();
    
    else
    
        return null;
    


public List<MacIpPair> GetAllMacAddressesAndIppairs()

    List<MacIpPair> mip = new List<MacIpPair>();
    System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
    pProcess.StartInfo.FileName = "arp";
    pProcess.StartInfo.Arguments = "-a ";
    pProcess.StartInfo.UseShellExecute = false;
    pProcess.StartInfo.RedirectStandardOutput = true;
    pProcess.StartInfo.CreateNoWindow = true;
    pProcess.Start();
    string cmdOutput = pProcess.StandardOutput.ReadToEnd();
    string pattern = @"(?<ip>([0-9]1,3\.?)4)\s*(?<mac>([a-f0-9]2-?)6)";

    foreach (Match m in Regex.Matches(cmdOutput, pattern, RegexOptions.IgnoreCase))
    
        mip.Add(new MacIpPair()
        
            MacAddress = m.Groups["mac"].Value,
            IpAddress = m.Groups["ip"].Value
        );
    

    return mip;

public struct MacIpPair

    public string MacAddress;
    public string IpAddress;

【讨论】:

这是正确的答案。对于帖子而不是@Macro Mp 答案.....为什么不选择这个作为答案? 为什么它不显示自己的 PC MAC 但找到所有其他的? @Khan 可能是因为您已经知道自己的 IP 和 MAC,因此无需将自己的 IP 存储在 ARP 表中 ***.com/questions/850650/… 我明白,但这不适用于包含 [a-f0-9]2 的表达式,这就是我将其更改为 [a-f0-9]1,2 的原因跨度> 【参考方案2】:
using System.Net;
using System.Runtime.InteropServices;

[DllImport("iphlpapi.dll", ExactSpelling = true)]
public static extern int SendARP(int DestIP, int SrcIP, [Out] byte[] pMacAddr, ref int PhyAddrLen);

try

    IPAddress hostIPAddress = IPAddress.Parse("XXX.XXX.XXX.XX");
    byte[] ab = new byte[6];
    int len = ab.Length, 
        r = SendARP((int)hostIPAddress.Address, 0, ab, ref len);
    Console.WriteLine(BitConverter.ToString(ab, 0, 6));

catch (Exception ex)  

或使用 PC 名称

try
      
           Tempaddr = System.Net.Dns.GetHostEntry("DESKTOP-xxxxxx");
      
      catch (Exception ex)  
      byte[] ab = new byte[6];
      int len = ab.Length, r = SendARP((int)Tempaddr.AddressList[1].Address, 0, ab, ref len);
        Console.WriteLine(BitConverter.ToString(ab, 0, 6));

【讨论】:

这是满足我当前需求的最佳示例。这确实有一个缺点,即它只假设 IPv4。此外,在 .Net Framework 4.7.2 中,不推荐使用 IPAddress.Address。使用它作为替代: uint ipAddress = BitConverter.ToUInt32(hostIPAddress.GetAddressBytes(), 0);同样,这假定 IPv4 并且不适用于 IPv6。【参考方案3】:

只是公认方法的性能更好的版本。

    public string GetMacByIp( string ip )
    
        var pairs = this.GetMacIpPairs();

        foreach( var pair in pairs )
        
            if( pair.IpAddress == ip )
                return pair.MacAddress;
        

        throw new Exception( $"Can't retrieve mac address from ip: ip" );
    

    public IEnumerable<MacIpPair> GetMacIpPairs()
    
        System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
        pProcess.StartInfo.FileName = "arp";
        pProcess.StartInfo.Arguments = "-a ";
        pProcess.StartInfo.UseShellExecute = false;
        pProcess.StartInfo.RedirectStandardOutput = true;
        pProcess.StartInfo.CreateNoWindow = true;
        pProcess.Start();

        string cmdOutput = pProcess.StandardOutput.ReadToEnd();
        string pattern = @"(?<ip>([0-9]1,3\.?)4)\s*(?<mac>([a-f0-9]2-?)6)";

        foreach( Match m in Regex.Matches( cmdOutput, pattern, RegexOptions.IgnoreCase ) )
        
            yield return new MacIpPair()
            
                MacAddress = m.Groups[ "mac" ].Value,
                IpAddress = m.Groups[ "ip" ].Value
            ;
        
    

    public struct MacIpPair
    
        public string MacAddress;
        public string IpAddress;
    

【讨论】:

【参考方案4】:

根据 Marco Mp 的上述评论,已使用 ARP 表。 arp class

【讨论】:

1.您的问题要求“获取 IP 并查找 MAC 地址”,它需要 ARP 而不是 RARP(获取 MAC 并返回您当前使用的 IP/主机)。您如何结束-上面这儿? 2.您所指的站点使用了错误的进程定义(MAC到IP是RARP而不是ARP)...

以上是关于从 C# 中的 IP 获取本地网络上的机器 MAC 地址的主要内容,如果未能解决你的问题,请参考以下文章

C#通过本地IP获取本地MAC地址(多个接口)

C# - 连接到 (RAS) *** 时如何获取 IP 地址

C# - 识别另一个网络上的计算机

从已知的MAC地址获取网络接口卡(NIC)(并获取该NIC上的IP地址)

如何使用 C# 确定本地网络上的哪些 IP 地址是静态/动态的?

确定最终用户机器 MAC 地址和 IP 地址(本地和 ISP)