在C#中获取机器MAC地址的可靠方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/850650/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reliable method to get machine's MAC address in C#
提问by
I need a way to get a machine's MAC address regardless of the OS it is running using C#. Application will need to work on XP/Vista/Win7 32 and 64 bit as well as on those OSs but with a foreign language default. Many of the C# commands and OS queries don't work across OS. Any ideas? I have been scraping the output of "ipconfig /all" but this is terribly unreliable as the output format differs on every machine.
我需要一种方法来获取机器的 MAC 地址,而不管它使用 C# 运行的操作系统如何。应用程序需要在 XP/Vista/Win7 32 位和 64 位以及这些操作系统上运行,但默认使用外语。许多 C# 命令和操作系统查询不能跨操作系统工作。有任何想法吗?我一直在抓取“ipconfig /all”的输出,但这非常不可靠,因为每台机器的输出格式都不同。
Thanks
谢谢
回答by Bayard Randel
The MACAddressproperty of the Win32_NetworkAdapterConfiguration WMI classcan provide you with an adapter's MAC address. (System.Management Namespace)
Win32_NetworkAdapterConfiguration WMI 类的MACAddress属性可以为您提供适配器的 MAC 地址。(系统管理命名空间)
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"
If you're not familiar with the WMI API (Windows Management Instrumentation), there's a good overview herefor .NET apps.
如果您不熟悉 WMI API(Windows Management Instrumentation),这里有一个关于 .NET 应用程序的很好的概述。
WMI is available across all version of windows with the .Net runtime.
WMI 可用于所有带有 .Net 运行时的 Windows 版本。
Here's a code example:
这是一个代码示例:
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());
}
}
回答by mmr
You could go for the NIC ID:
您可以查找 NIC ID:
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) {
if (nic.OperationalStatus == OperationalStatus.Up){
if (nic.Id == "yay!")
}
}
It's not the MAC address, but it is a unique identifier, if that's what you're looking for.
它不是 MAC 地址,但它是一个唯一标识符,如果这就是您要查找的。
回答by ChrisW
ipconfig.exe
is implemented using various DLLs including iphlpapi.dll
... Googling for iphlpapi
reveals a corresponding Win32 API documented in MSDN.
ipconfig.exe
使用各种 DLL 实现,包括iphlpapi.dll
......谷歌搜索iphlpapi
显示 MSDN 中记录的相应 Win32 API。
回答by Brian Duncan
WMI is the best solution if the machine you are connecting to is a windows machine, but if you are looking at a linux, mac, or other type of network adapter, then you will need to use something else. Here are some options:
如果您连接的机器是 Windows 机器,WMI 是最好的解决方案,但如果您正在查看 linux、mac 或其他类型的网络适配器,那么您将需要使用其他东西。以下是一些选项:
- Use the DOS command nbtstat -a . Create a process, call this command, parse the output.
- First Ping the IP to make sure your NIC caches the command in it's ARP table, then use the DOS command arp -a . Parse the output of the process like in option 1.
- Use a dreaded unmanaged call to sendarp in the iphlpapi.dll
- 使用 DOS 命令 nbtstat -a 。创建一个进程,调用这个命令,解析输出。
- 首先 Ping IP 以确保您的 NIC 在其 ARP 表中缓存命令,然后使用 DOS 命令 arp -a 。像选项 1 一样解析进程的输出。
- 在 iphlpapi.dll 中使用对 sendarp 的可怕的非托管调用
Heres a sample of item #3. This seems to be the best option if WMI isn't a viable solution:
这是第 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);
}
To give credit where it is due, this is the basis for that code: http://www.pinvoke.net/default.aspx/iphlpapi.sendarp#
为了在到期时给予信用,这是该代码的基础:http: //www.pinvoke.net/default.aspx/iphlpapi.sendarp#
回答by blak3r
Here's some C# code which returns the MAC address of the first operational network interface. Assuming the NetworkInterface
assembly is implemented in the runtime (i.e. Mono) used on other operating systems then this would work on other operating systems.
这是一些 C# 代码,它返回第一个操作网络接口的 MAC 地址。假设NetworkInterface
程序集是在其他操作系统上使用的运行时(即 Mono)中实现的,那么这将适用于其他操作系统。
New version: returns the NIC with the fastest speed that also has a valid MAC address.
新版本:返回速度最快且具有有效 MAC 地址的 NIC。
/// <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;
}
Original Version: just returns the first one.
原始版本:只返回第一个。
/// <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;
}
The only thing I don't like about this approach is if you have like a Nortel Packet Miniport or some type of VPN connection it has the potential of being chosen. As far as I can tell, there is no way to distinguish an actual physical device's MAC from some type of virtual network interface.
我唯一不喜欢这种方法的地方是,如果您喜欢 Nortel Packet Miniport 或某种类型的 VPN 连接,它就有可能被选中。据我所知,无法将实际物理设备的 MAC 与某种类型的虚拟网络接口区分开来。
回答by Mohammed A. Fadil
Cleaner solution
更清洁的解决方案
var macAddr =
(
from nic in NetworkInterface.GetAllNetworkInterfaces()
where nic.OperationalStatus == OperationalStatus.Up
select nic.GetPhysicalAddress().ToString()
).FirstOrDefault();
Or:
或者:
String firstMacAddress = NetworkInterface
.GetAllNetworkInterfaces()
.Where( nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback )
.Select( nic => nic.GetPhysicalAddress().ToString() )
.FirstOrDefault();
回答by AVee
We use WMI to get the mac address of the interface with the lowest metric, e.g. the interface windows will prefer to use, like this:
我们使用 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;
}
Or in Silverlight (needs elevated trust):
或者在 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;
}
回答by Detlef
I really like AVee's solution with the lowest IP connection metric! But if a second nic with the same metric is installed, the MAC comparison could fail...
我真的很喜欢 AVee 具有最低 IP 连接指标的解决方案!但是如果安装了具有相同指标的第二个 nic,MAC 比较可能会失败......
Better you store the description of the interface with the MAC. In later comparisons you can identify the right nic by this string. Here is a sample code:
最好用 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;
}
回答by Tono Nam
let's say I have a TcpConnection using my local ip of 192.168.0.182. Then if I will like to know the mac address of that NIC I will call the meothod as: GetMacAddressUsedByIp("192.168.0.182")
假设我有一个使用本地 IP 192.168.0.182 的 TcpConnection。然后,如果我想知道该 NIC 的 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;
}
回答by Tony
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;
}