在C#中获取机器MAC地址的可靠方法


131

无论使用C#运行的操作系统如何,我都需要一种获取机器的MAC地址的方法。应用程序将需要在XP / Vista / Win7 32和64位以及这些OS上运行,但默认使用外语。许多C#命令和OS查询不适用于整个OS。有任何想法吗?我一直在抓取“ ipconfig / all”的输出,但这是非常不可靠的,因为每台计算机上的输出格式都不同。

谢谢


7
当您跨操作系统说时,是指跨不同的Microsoft操作系统吗?
约翰·韦尔顿

Answers:


136

清洁剂

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();

44
或者lambda,如果那是你的事!return NetworkInterface.GetAllNetworkInterfaces().Where(nic => nic.OperationalStatus == OperationalStatus.Up).Select(nic => nic.GetPhysicalAddress().ToString()).FirstOrDefault();(如果不是您的事,那应该是您的事。)
GONeale 2012年

7
最快的最快方法: 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();
Graham Laight

1
首先选择并不总是最好的选择。选择最常用的连接:stackoverflow.com/a/51821927/3667
Ramunas

优化说明:您可以FirstOrDefault在final之前致电Select。这样,它只会获取物理地址并针对NetworkInterface您实际获得的地址进行序列化。别忘了在FirstOrDefault。后面添加null检查(?)。
GregaMohorko '18

一种计算速度更快的方法,您无需评估所有与给定条件匹配的网络,只需要它们中的第一个即可: NetworkInterface .GetAllNetworkInterfaces() .FirstOrDefault(nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback)? .GetPhysicalAddress().ToString();
Alessandro Muzzi,

80

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

新版本:以最快的速度返回NIC,同时具有有效的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;
}

对于这种方法,我唯一不喜欢的是,如果您拥有北电分组迷你端口或某种类型的VPN连接,则有可能被选择。据我所知,无法将实际物理设备的MAC与某种类型的虚拟网络接口区分开。


6
不要只选择第一个操作界面。这可能会返回环回接口,偶尔连接的3G卡等,这些可能不是您想要的。NetworkInterfaceType(msdn.microsoft.com/en-us/library/…)将为您提供有关NetworkInterface连接的更多信息,以便您可以做出更明智的选择。还请记住,一台机器上可能有许多活动连接,并且它们的顺序可能不可预测。
戴夫·R.

@DaveR。我查看了NetworkInterfaceType,即使从我的经验来看,它实际上是一个虚拟适配器,它基本上总是返回以太网,因此我发现它几乎没有用。
blak3r 2012年

1
您应该选择具有最低GatewayMetric的接口。这应该是具有“最快,最可靠或最不占用资源的路由”的连接。基本上,它将为您提供Windows首选使用的界面。但是,我认为您实际上需要WMI。我会看看我能否
使它

6
为了完整using System.Net.NetworkInformation;
起见,

1
FWIW,如果您安装了千兆网卡和Hyper-V,则还将具有10千兆位虚拟网卡。:)要解决的难题...
Christopher Painter

10

Win32_NetworkAdapterConfiguration WMI类MACAddress属性可以为您提供适配器的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应用程序的良好概述

.Net运行时可在所有版本的Windows中使用WMI。

这是一个代码示例:

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());
         }
     }

9

如果要连接的计算机是Windows计算机,则WMI是最佳解决方案,但是如果您正在查看linux,mac或其他类型的网络适配器,则需要使用其他工具。以下是一些选项:

  1. 使用DOS命令nbtstat -a。创建一个进程,调用此命令,解析输出。
  2. 首先对IP进行Ping操作,以确保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相同的东西,而这正是我所需要的!
QueueHammer

在选项1和2中,如果您在Windows计算机上,则表示DOS命令,而在Linux或Mac上则是等效的命令,对吗?
Raikol Amaro

8

我们使用WMI来获取具有最低度量标准的接口的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
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地址,对吗?
Nate Pet

它获取主机,服务器的MAC地址。
托尼,

6

恕我直言,返回第一个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

此方法将确定用于连接到指定的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年

  • 添加了注释以解释代码。
  • 更正为与使用映射到IPV6的IPV4的较新操作系统一起使用(例如Windows 10)。
  • 减少嵌套。
  • 升级后的代码使用“ var”。

1
这非常有趣,我将尝试一下,因为在这种情况下,我希望客户端发现a)用于与服务器通信的源地址(它不一定是通过Internet)和b)什么是MAC地址是提供此IP地址的NIC ...
Brian B

5

您可以输入NIC ID:

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

它不是MAC地址,但如果您正在寻找的话,它是唯一的标识符。


2

我非常喜欢具有最低IP连接指标的AVee解决方案!但是,如果安装了另一个具有相同度量标准的网卡,则MAC比较可能会失败...

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

   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;
    }

2

假设我有一个使用本地IP 192.168.0.182的TcpConnection。然后,如果我想知道该NIC的mac地址,则将meothod称为: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;
    }

这效率不高...我不建议您这样做。
伊万德罗IG Jao

2

真的很讨厌挖这个旧帖子,但是我觉得这个问题值得针对Windows 8-10的另一个答案。

使用NetworkInformationWindows.Networking.Connectivity命名空间,你可以得到网络适配器窗口的ID被使用。然后,您可以从前面提到的GetAllNetworkInterfaces()中获取接口MAC地址。

这在Windows Store Apps中将不起作用,因为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;
}

2
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);

2
可以通过简要解释代码的作用以及如何解决问题来改善此答案。
格雷格难以置信'18

1

更改了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;
}


0

ipconfig.exe可以使用各种DLL实现,包括iphlpapi.dll...。Google搜索用于iphlpapi揭示MSDN中记录的相应Win32 API。


0

试试这个:

    /// <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;
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.