网上能够找到不少使用C#语言获取本机MAC地址与IP地址的代码,在这里说一下个人使用心得。html
在windows控制台中使用命令ipconfig /all能够查到本机的网络配置。但其中的网络有不少是不用的,可能你的电脑链接外网只用到了其中的一个网络。所以咱们要获取的是实际链接外网的网络链接。windows
第一种方式安全
使用WMI(Windows Management Instrumentation)从对象Win32_NetworkAdapterConfiguration中获取MAC和IP。此对象在MSDN上的介绍页面见:服务器
https://msdn.microsoft.com/en-us/library/aa394217(v=vs.85).aspx网络
代码以下:函数
/// <summary> /// 获取当前激活网络的MAC地址、IPv4地址、IPv6地址 - 方法1 /// </summary> /// <param name="mac">网卡物理地址</param> /// <param name="ipv4">IPv4地址</param> /// <param name="ipv6">IPv6地址</param> public static void GetActiveIpAndMac1(out string mac, out string ipv4, out string ipv6) { mac = ""; ipv4 = ""; ipv6 = ""; //须要引用:System.Management; ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration"); ManagementObjectCollection moc = mc.GetInstances(); foreach (ManagementObject mo in moc) { if (mo["IPEnabled"].ToString() == "True") { //获取MAC地址,每两位中间用横线【-】隔开 mac = mo["MacAddress"].ToString().Replace(":", "-"); string[] ipAddrs = mo["IPAddress"] as string[]; if (ipAddrs != null && ipAddrs.Length >= 1) { //获取IPv4地址,4个十进制数字,中间用英文句号【.】隔开 ipv4 = ipAddrs[0]; } if (ipAddrs != null && ipAddrs.Length >= 2) { //获取IPv6地址,5个十六进制数字,中间用冒号【:】隔开 ipv6 = ipAddrs[1]; } break; } } }
注意事项:工具
一、使用此方法需添加引用:System.Management测试
二、在可用网络列表中,上述代码只获取了第一个启用的网络配置的MAC地址与IP地址,如要获取指定的MAC或IP,还需进一步添加限制条件spa
三、此方法获取的MAC地址格式为XX-XX-XX-XX-XX-XX,IP地址格式为XXX.XXX.XXX.XXX日志
四、此方法在大多数计算机上可正常使用,但昨天发现一台机器调用此方法时报错“拒绝访问”,异常调用堆栈以下:
堆栈: 在 System.Management.ManagementException.ThrowWithExtendedInfo(ManagementStatus errorCode) 在 System.Management.ManagementObjectCollection.ManagementObjectEnumerator.MoveNext() 在 ... ...
从异常的描述看报此异常应是由于权限不够,此问题的缘由详见本篇博客附文。
第二种方式
使用NetworkInterface获取本地网络接口。
代码以下:
/// <summary> /// 获取当前激活网络的MAC地址、IPv4地址、IPv6地址 - 方法2 /// </summary> /// <param name="mac">网卡物理地址</param> /// <param name="ipv4">IPv4地址</param> public static void GetActiveIpAndMac2(out string mac, out string ipv4, out string ipv6) { mac = ""; ipv4 = ""; ipv6 = ""; //须要引用:System.Net.NetworkInformation NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface adapter in nics) { IPInterfaceProperties adapterProperties = adapter.GetIPProperties(); UnicastIPAddressInformationCollection allAddress = adapterProperties.UnicastAddresses; if (allAddress.Count > 0) { if (adapter.OperationalStatus == OperationalStatus.Up) { mac = adapter.GetPhysicalAddress().ToString(); foreach (UnicastIPAddressInformation addr in allAddress) { if (addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { ipv4 = addr.Address.ToString(); } if (addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) { ipv6 = addr.Address.ToString(); } } if (string.IsNullOrWhiteSpace(mac) || (string.IsNullOrWhiteSpace(ipv4) && string.IsNullOrWhiteSpace(ipv6))) { mac = ""; ipv4 = ""; ipv6 = ""; continue; } else { if (mac.Length == 12) { mac = string.Format("{0}-{1}-{2}-{3}-{4}-{5}", mac.Substring(0, 2), mac.Substring(2, 2), mac.Substring(4, 2), mac.Substring(6, 2), mac.Substring(8, 2), mac.Substring(10, 2)); } break; } } } } }
注意事项:
一、使用此方法需添加引用:System.Net.NetworkInformation
二、同方法一同样,在可用网络列表中,上述代码只获取了第一个启用的网络配置的MAC地址与IP地址,如要获取指定的MAC或IP,还需进一步添加限制条件
三、此方法获取的MAC与IP可能与方法1不同,出现此问题的缘由是,一个电脑可能有多个网络配置处于激活状态,而方法1与方法2使用foreach遍历的顺序是不同的。获取的第一个可用的MAC和IP并不必定是同一个。个人电脑上以前为了在互联网上和朋友玩局域网游戏,安装过nMatrix工具,以前在个人电脑上使用方法1获取的第一个配置是无线网络适配器的MAC和IP,使用方法2获取的第一个配置是nMatrix工具的MAC和IP。
四、此方法获取的MAC地址格式为XX-XX-XX-XX-XX-XX,IP地址格式为XXX.XXX.XXX.XXX
我为了测试还写过一个遍历网络的函数,也列在这里:
/// <summary> /// 打印网络配置列表 /// </summary> public static void PrintNetwork() { NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface adapter in nics) { IPInterfaceProperties adapterProperties = adapter.GetIPProperties(); UnicastIPAddressInformationCollection allAddress = adapterProperties.UnicastAddresses; if (allAddress.Count > 0) { Console.WriteLine("================="); Console.WriteLine("Name:" + adapter.Name); Console.WriteLine("Description:" + adapter.Description); Console.WriteLine("NetworkInterfaceType:" + adapter.NetworkInterfaceType.ToString()); Console.WriteLine("OperationalStatus:" + adapter.OperationalStatus.ToString()); Console.WriteLine("Mac:" + adapter.GetPhysicalAddress().ToString()); foreach (UnicastIPAddressInformation addr in allAddress) { if (addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { Console.WriteLine("Address(V4):" + addr.Address); } if (addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) { Console.WriteLine("Address(V6):" + addr.Address); } } } } }
测试程序
创建一个Windows控制台应用程序,将上面的函数放入到类NetworkHelper中,可测试运行效果,代码以下:
using System; using System.Collections.Generic; using System.Linq; using System.Net.NetworkInformation; using System.Text; namespace GetNetworkInfoTest { class Program { static void Main(string[] args) { try { Console.WriteLine("方法1:WMI"); string mac; string ipv4; string ipv6; NetworkHelper.GetActiveIpAndMac1(out mac, out ipv4, out ipv6); Console.WriteLine("mac:" + mac); Console.WriteLine("ipv4:" + ipv4); Console.WriteLine("ipv6:" + ipv6); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } try { Console.WriteLine("方法2:NetworkInterface"); string mac; string ipv4; string ipv6; NetworkHelper.GetActiveIpAndMac2(out mac, out ipv4, out ipv6); Console.WriteLine("mac:" + mac); Console.WriteLine("ipv4:" + ipv4); Console.WriteLine("ipv6:" + ipv6); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } try { NetworkHelper.PrintNetwork(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } Console.Read(); } } }
在实际项目中的应用
一、由于方法1有可能由于用户电脑的安全设置被禁用,所以我建议在获取MAC地址时采用如下方式:
方式①:直接使用方法二获取MAC与IP
方式②:因个人程序以前使用的是方法一,所以采用此法改进:先使用方法一(WMI)获取MAC与IP,如使用方法一获取不成功,捕获异常后使用方法二(NetworkInterface)再次尝试获取,如方法二也获取不成功,则认为地址获取失败,记录相关日志,并进行相关处理。
二、这两个方法都没法直接断定哪个网络是真正链接外网的,所以如需肯定真正链接外部网络的MAC和IP,须要具体问题具体分析。有一种实际场景,是要断定只有指定MAC的电脑才能链接到服务,实现此场景须要客户端程序采集当前计算机全部激活状态的MAC,并与服务器端报错的MAC进行比较,只要有一个MAC匹配,就认定为此电脑是有权限的。
附文:方法1中使用WMI获取MAC地址时出现“拒绝访问”问题的排查(2016年12月27日11时补充)
后来我写了一个VBS脚本测试这个问题:
strComputer = "." Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2") Set colItems = objWMIService.ExecQuery("Select * from Win32_NetworkAdapterConfiguration",,48) For Each objItem in colItems If objItem.MACAddress <> "" Then Wscript.Echo "MACAddress: " & objItem.MACAddress End If Next
在出现问题的计算机上执行此段脚本,发现错误码为:0x80041003,问题缘由为“试图链接命名空间的进程若是没有必需的WMI权限”
有一篇文章对WMI问题讲得比较详细,可供参考:WMI问题全解(Windows管理规范)<转>
http://www.cnblogs.com/haiq/archive/2011/01/14/1935377.html
个人电脑能够正常执行上面的VBS脚本,我使用它复现出了此问题,方法以下:
一、使用管理员用户新建用户wmi_test,此时登陆用户wmi_test,该用户是能够正常执行上面的VBS脚本的
二、进入WMI控件设置,方法为:在桌面上用鼠标右键单击“计算机”,在右键菜单中选择“管理”,在左侧树形列表中,找到“计算机管理(本地)→服务和应用程序→WMI控件”,鼠标右键单击此项,选择“属性”
三、找到Root/CIMV2,点击“安全设置”,点击“添加”按钮,找到新建的用户,将该用户Root\CIMV2命名空间全部权限禁用
四、登陆用户wmi_test,如当前已登陆此用户则须要注销后从新登陆之。执行上面的VBS脚本,就会报错0x80041003了
END