Надежный способ получить MAC-адрес компьютера в C # - PullRequest
114 голосов
/ 12 мая 2009

Мне нужен способ получить MAC-адрес компьютера независимо от операционной системы, на которой он работает, используя C #. Приложение должно работать на XP / Vista / Win7 32 и 64-битных, а также на этих ОС, но с иностранным языком по умолчанию. Многие команды C # и запросы ОС не работают в разных ОС. Есть идеи? Я очищаю вывод «ipconfig / all», но это ужасно ненадежно, так как формат вывода отличается на каждой машине.

Спасибо

Ответы [ 16 ]

118 голосов
/ 05 октября 2011

Чистящее средство

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();
76 голосов
/ 13 октября 2009

Вот некоторый код 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-адрес реального физического устройства от некоторого типа интерфейса виртуальной сети.

10 голосов
/ 12 сентября 2009

WMI - лучшее решение, если компьютер, к которому вы подключаетесь, - это компьютер с Windows, но если вы смотрите на сетевой адаптер linux, mac или другого типа, вам нужно будет использовать что-то другое. Вот несколько вариантов:

  1. Используйте команду DOS nbtstat -a. Создайте процесс, вызовите эту команду, проанализируйте вывод.
  2. Сначала выполните Ping IP-адреса, чтобы убедиться, что сетевой адаптер кэширует команду в своей таблице ARP, затем используйте команду DOS arp -a. Разобрать выходные данные процесса, как в варианте 1.
  3. Используйте страшный неуправляемый вызов sendarp в iphlpapi.dll

Вот образец предмета № 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#

10 голосов
/ 12 мая 2009

Свойство MACAddress класса WMI Win32_NetworkAdapterConfiguration может предоставить вам 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.

WMI доступен во всех версиях Windows со средой исполнения .Net.

Вот пример кода:

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());
         }
     }
7 голосов
/ 21 июня 2012

Мы используем 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;
}
6 голосов
/ 14 января 2014
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;
}
5 голосов
/ 03 октября 2014

Мне нужно было получить MAC для фактического сетевого адаптера, используемого для подключения к Интернету; определить, какой интерфейс использовал WCF в моем клиентском приложении.

Я вижу здесь много ответов, но ни один из них не помог мне. Надеюсь, что этот ответ кому-нибудь поможет.

Это решение возвращает MAC-адрес сетевой карты, используемой для подключения к Интернету.

private static PhysicalAddress GetCurrentMAC(string allowedURL)
{
  TcpClient client = new TcpClient();
  client.Client.Connect(new IPEndPoint(Dns.GetHostAddresses(allowedURL)[0], 80));
  while(!client.Connected)
  {
    Thread.Sleep(500);  
  }
  IPAddress address2 = ((IPEndPoint)client.Client.LocalEndPoint).Address;
  client.Client.Disconnect(false);
  NetworkInterface[] allNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
  client.Close();
  if(allNetworkInterfaces.Length > 0)
  {
    foreach(NetworkInterface interface2 in allNetworkInterfaces)
    {
      UnicastIPAddressInformationCollection unicastAddresses = interface2.GetIPProperties().UnicastAddresses;
      if((unicastAddresses != null) && (unicastAddresses.Count > 0))
      {
        for(int i = 0; i < unicastAddresses.Count; i++)
          if(unicastAddresses[i].Address.Equals(address2))
            return interface2.GetPhysicalAddress();
      }
    }
  }
  return null;
}

Чтобы позвонить, вам нужно передать URL для подключения вот так:

PhysicalAddress mac = GetCurrentMAC("www.google.com");
4 голосов
/ 13 августа 2018

ИМХО возвращать первый 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;
}
4 голосов
/ 12 мая 2009

Вы можете перейти на NIC ID:

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

Это не MAC-адрес, но это уникальный идентификатор, если это то, что вы ищете.

2 голосов
/ 04 июля 2016

Очень не хочется выкапывать этот старый пост, но я чувствую, что вопрос заслуживает другого ответа, специфичного для windows 8-10.

Используя NetworkInformation из пространства имен Windows.Networking.Connectivity , вы можете получить идентификатор используемого сетевого адаптера Windows. Затем вы можете получить MAC-адрес интерфейса из ранее упомянутого GetAllNetworkInterfaces ().

Это не будет работать в приложениях Магазина Windows, так как NetworkInterface в System.Net.NetworkInformation не предоставляет 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;
}
...