文档章节

C#:获取本机的MAC地址与IP地址

北风其凉
 北风其凉
发布于 2016/12/27 10:04
字数 1887
阅读 1159
收藏 0

网上可以找到很多使用C#语言获取本机MAC地址与IP地址的代码,在这里说一下我的使用心得。

在windows控制台中使用命令ipconfig /all可以查到本机的网络配置。但其中的网络有很多是不用的,可能你的电脑连接外网只用到了其中的一个网络。因此我们要获取的是实际连接外网的网络连接。

第一种方式

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

注意事项:

1、使用此方法需添加引用:System.Management

2、在可用网络列表中,上述代码只获取了第一个启用的网络配置的MAC地址与IP地址,如要获取指定的MAC或IP,还需进一步添加限制条件

3、此方法获取的MAC地址格式为XX-XX-XX-XX-XX-XX,IP地址格式为XXX.XXX.XXX.XXX

4、此方法在大多数计算机上可正常使用,但昨天发现一台机器调用此方法时报错“拒绝访问”,异常调用堆栈如下:

堆栈:   在 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;
                }
            }
        }
    }
}

注意事项:

1、使用此方法需添加引用:System.Net.NetworkInformation

2、同方法一一样,在可用网络列表中,上述代码只获取了第一个启用的网络配置的MAC地址与IP地址,如要获取指定的MAC或IP,还需进一步添加限制条件

3、此方法获取的MAC与IP可能与方法1不一样,出现此问题的原因是,一个电脑可能有多个网络配置处于激活状态,而方法1与方法2使用foreach遍历的顺序是不一样的。获取的第一个可用的MAC和IP并不一定是同一个。我的电脑上之前为了在互联网上和朋友玩局域网游戏,安装过nMatrix工具,之前在我的电脑上使用方法1获取的第一个配置是无线网络适配器的MAC和IP,使用方法2获取的第一个配置是nMatrix工具的MAC和IP。

4、此方法获取的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、因为方法1有可能因为用户电脑的安全设置被禁用,因此我建议在获取MAC地址时采用以下方式:

方式①:直接使用方法二获取MAC与IP

方式②:因我的程序之前使用的是方法一,因此采用此法改进:先使用方法一(WMI)获取MAC与IP,如使用方法一获取不成功,捕获异常后使用方法二(NetworkInterface)再次尝试获取,如方法二也获取不成功,则认为地址获取失败,记录相关日志,并进行相关处理。

2、这两个方法都无法直接判定哪一个网络是真正连接外网的,因此如需确定真正连接外部网络的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脚本,我使用它复现出了此问题,方法如下:

1、使用管理员用户新建用户wmi_test,此时登录用户wmi_test,该用户是可以正常执行上面的VBS脚本的

2、进入WMI控件设置,方法为:在桌面上用鼠标右键单击“计算机”,在右键菜单中选择“管理”,在左侧树形列表中,找到“计算机管理(本地)→服务和应用程序→WMI控件”,鼠标右键单击此项,选择“属性”

3、找到Root/CIMV2,点击“安全设置”,点击“添加”按钮,找到新建的用户,将该用户Root\CIMV2命名空间所有权限禁用

4、登录用户wmi_test,如当前已登录此用户则需要注销后重新登录之。执行上面的VBS脚本,就会报错0x80041003了

END

© 著作权归作者所有

北风其凉

北风其凉

粉丝 121
博文 497
码字总数 462305
作品 4
朝阳
程序员
私信 提问
加载中

评论(1)

沐风歌
沐风歌
感谢分享!
我觉得大多数情况下,方法二都是可行的。
获取远程网卡MAC地址

出自: http://blog.joycode.com/liuhuimiao/ 朋友mingal急问我有关获取远程网卡MAC地址的ASP.net实现。我一开始以为是获取本机MAC地址,说了几种方法给他。由于他还需要获取服务器(本机)相...

晨曦之光
2012/03/09
1K
0
Python获取网卡信息(名称、MAC、IP、网关等)

“人生苦短,我用Python”。Python的高效有一部分是跟它丰富的模块分不开的。Python有很多第三方模块可以帮助我们完成一些事情,减少开发时间。 Python pypi库中一个模块名字叫“netifaces”...

urey_pp
2016/11/03
0
0
互联网协议入门(二)

上一篇文章分析了互联网的总体构思,从下至上,每一层协议的设计思想。 这是从设计者的角度看问题,今天我想切换到用户的角度,看看用户是如何从上至下,与这些协议互动的。 ==============...

阮一峰
2012/06/11
0
0
互联网协议入门(二)

作者:阮一峰 日期:2012年6月11日 上一篇文章分析了互联网的总体构思,从下至上,每一层协议的设计思想。 这是从设计者的角度看问题,今天我想切换到用户的角度,看看用户是如何从上至下,与...

zhleven
2017/01/19
0
0
03-WIFI通讯获取Wifi名称及ip地址

在上一小节中,笔者在介绍wifi通讯流程中介绍到,wifi通讯的本质就是由路由器(wifi芯片)担任局域网服务器来实现多个客户端之间的数据转发,所以第一步我们的服务器需要去监听局域网内的端口...

u013263917
2017/08/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Java 8 Stream Api 中的 skip 和 limit 操作

1. 前言 Java 8 Stream API 中的skip()和limit()方法具有类似的作用。它们都是对流进行裁剪的中间方法。今天我们来探讨一下这两个方法。 2. skip() skip(lang n) 是一个跳过前 n 个元素的...

码农小胖哥
36分钟前
1
0
看中华小当家第二集片段记录

最近正好在学习做饭,看看这片子,燃烧燃烧做饭的热情 哈哈,以下是摘的一些句子和个人理解 My name is Liu Mao Xing . More commonly known as Mao. 个人理解:我的名字叫 刘昴星, (commo...

T型人才追梦者
40分钟前
3
0
Python基础-6

1、注释 # 单行注释'''多行注释'''"""多行注释"""# 中文编码声明注释 ,在文件开头加上下面这行注释# encoding=utf-8或者# -*- encoding:utf-8 -*- (-*- 只是为了美观,没有实际......

zfskkk
41分钟前
5
0
我的这半年 / 2018 七夕著

浑然不觉,竟已至七夕, 今年已经过了一半 , 突然想给自己记录点什么 , 回顾下我的2018, 我的这上半年. 2018的第一件记事得从一月份下旬的那场大雪说起 , 一觉醒来 , 窗外整个银装素裹 , 在此之...

gxLong
45分钟前
3
0
NSS支持的数据库

NSS,简写自Name Service Switch。我把它译为“名字服务中心”。 在*nix操作系统中,NSS是C语言库(Library C或者glibc)的一部分,用以寻找名字。比如说,我们运行ls -lh查看一个目录中的文...

大别阿郎
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部