C/C++ 获取主机网卡MAC地址

简介: MAC地址(Media Access Control address),又称为物理地址或硬件地址,是网络适配器(网卡)在制造时被分配的全球唯一的48位地址。这个地址是数据链路层(OSI模型的第二层)的一部分,用于在局域网(LAN)中唯一标识网络设备。获取网卡地址主要用于网络标识和身份验证的目的。MAC地址是一个唯一的硬件地址,通常由网卡的制造商在制造过程中分配。通过获取MAC地址可以判断当前主机的唯一性可以与IP地址绑定并实现网络准入控制。在Windows平台下获取MAC地址的方式有很多,获取MAC地址的常见方式包括使用操作系统提供的网络API(如Windows的GetAdaptersAddr

MAC地址(Media Access Control address),又称为物理地址或硬件地址,是网络适配器(网卡)在制造时被分配的全球唯一的48位地址。这个地址是数据链路层(OSI模型的第二层)的一部分,用于在局域网(LAN)中唯一标识网络设备。获取网卡地址主要用于网络标识和身份验证的目的。MAC地址是一个唯一的硬件地址,通常由网卡的制造商在制造过程中分配。通过获取MAC地址可以判断当前主机的唯一性可以与IP地址绑定并实现网络准入控制。

在Windows平台下获取MAC地址的方式有很多,获取MAC地址的常见方式包括使用操作系统提供的网络API(如Windows的GetAdaptersAddresses和GetAdaptersInfo),NetBIOS API,系统命令(如ipconfig /all),ARP缓存表查询,第三方库(如WinPcap或Libpcap),以及在编程语言中使用网络库。

首先第一种获取方法封装GetMacByGetAdaptersAddresses函数,该功能的实现通过调用系统中的GetAdaptersAddresses获取计算机的MAC地址。

该函数首先分配内存来存储适配器信息,然后调用 GetAdaptersAddresses 函数获取适配器信息。如果内存不足,它会重新分配足够的内存并再次调用该函数。接着,它遍历返回的适配器信息,找到第一个物理地址长度为6的适配器,然后将其MAC地址以格式化字符串的形式存储在传入的 macOUT 变量中。最后,释放分配的内存,并返回一个布尔值。

#include <iostream>
#include <winsock2.h>
#include <iphlpapi.h>
#include <string>

#pragma comment(lib, "Netapi32.lib")
#pragma comment(lib, "IPHLPAPI.lib")

using namespace std;

bool GetMacByGetAdaptersAddresses(std::string& macOUT)
{
   
   
    bool ret = false;

    ULONG outBufLen = sizeof(IP_ADAPTER_ADDRESSES);
    PIP_ADAPTER_ADDRESSES pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
    if (pAddresses == NULL)
        return false;

    if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW)
    {
   
   
        free(pAddresses);
        pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
        if (pAddresses == NULL)
            return false;
    }

    if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == NO_ERROR)
    {
   
   
        for (PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses; pCurrAddresses != NULL; pCurrAddresses = pCurrAddresses->Next)
        {
   
   
            // 确保MAC地址的长度为 00-00-00-00-00-00
            if (pCurrAddresses->PhysicalAddressLength != 6)
                continue;
            char acMAC[32];
            sprintf(acMAC, "%02X-%02X-%02X-%02X-%02X-%02X",
                int(pCurrAddresses->PhysicalAddress[0]),
                int(pCurrAddresses->PhysicalAddress[1]),
                int(pCurrAddresses->PhysicalAddress[2]),
                int(pCurrAddresses->PhysicalAddress[3]),
                int(pCurrAddresses->PhysicalAddress[4]),
                int(pCurrAddresses->PhysicalAddress[5]));
            macOUT = acMAC;
            ret = true;
            break;
        }
    }

    free(pAddresses);
    return ret;
}

int main(int argc, char *argv[])
{
   
   
    std::string refBuffer;

    GetMacByGetAdaptersAddresses(refBuffer);
    std::cout << "Mac地址: " << refBuffer << std::endl;

    system("pause");
    return 0;
}

第二种方式GetMacByGetAdaptersInfo函数,通过调用系统的GetAdaptersInfo获取计算机的主网卡的MAC地址。函数首先分配内存来存储适配器信息,然后调用GetAdaptersInfo获取适配器信息。如果内存不足,它会重新分配足够的内存并再次调用该函数。接着,它遍历返回的适配器信息,找到第一个类型为以太网且物理地址长度为6的适配器,然后将其MAC地址以格式化字符串的形式存储在传入的macOUT变量中。最后,释放分配的内存,并返回一个布尔值。

#define _CRT_SECURE_NO_WARNINGS
#define _WIN32_DCOM
#define _CRT_NONSTDC_NO_DEPRECATE

#include <iostream>
#include <winsock2.h>
#include <iphlpapi.h>
#include <string>

#pragma comment(lib, "Netapi32.lib")
#pragma comment(lib, "IPHLPAPI.lib")

using namespace std;

bool GetMacByGetAdaptersInfo(std::string& macOUT)
{
   
   
    bool ret = false;

    ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
    PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO));
    if (pAdapterInfo == NULL)
        return false;

    if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
    {
   
   
        free(pAdapterInfo);
        pAdapterInfo = (IP_ADAPTER_INFO*)malloc(ulOutBufLen);
        if (pAdapterInfo == NULL)
            return false;
    }

    if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == NO_ERROR)
    {
   
   
        for (PIP_ADAPTER_INFO pAdapter = pAdapterInfo; pAdapter != NULL; pAdapter = pAdapter->Next)
        {
   
   
            // 确保是以太网
            if (pAdapter->Type != MIB_IF_TYPE_ETHERNET)
                continue;
            // 确保MAC地址的长度为 00-00-00-00-00-00
            if (pAdapter->AddressLength != 6)
                continue;
            char acMAC[32];
            sprintf(acMAC, "%02X-%02X-%02X-%02X-%02X-%02X",
                int(pAdapter->Address[0]),
                int(pAdapter->Address[1]),
                int(pAdapter->Address[2]),
                int(pAdapter->Address[3]),
                int(pAdapter->Address[4]),
                int(pAdapter->Address[5]));
            macOUT = acMAC;
            ret = true;
            break;
        }
    }

    free(pAdapterInfo);
    return ret;
}

int main(int argc, char *argv[])
{
   
   
    std::string refBuffer;

    GetMacByGetAdaptersInfo(refBuffer);
    std::cout << "Mac地址: " << refBuffer << std::endl;

    system("pause");
    return 0;
}

第三种封装一个GetMacByNetBIOS函数,其使用NetBIOS API获取指定适配器号(adapterNum)的MAC地址。函数首先通过NCBRESET命令重置指定网卡以便进行查询。接着,使用NCBASTAT命令获取接口卡的状态块,其中包含了适配器的物理地址。如果NetBIOS调用成功,将适配器的MAC地址以格式化字符串的形式存储在传入的macOUT变量中,最后返回一个布尔值。

#include <iostream>
#include <winsock2.h>
#include <iphlpapi.h>
#include <string>

#pragma comment(lib, "Netapi32.lib")
#pragma comment(lib, "IPHLPAPI.lib")

using namespace std;

bool GetAdapterInfo(int adapterNum, std::string& macOUT)
{
   
   
    NCB Ncb;
    memset(&Ncb, 0, sizeof(Ncb));

    // 重置网卡 以便我们可以查询
    Ncb.ncb_command = NCBRESET;
    Ncb.ncb_lana_num = adapterNum;
    if (Netbios(&Ncb) != NRC_GOODRET)
        return false;

    // 准备取得接口卡的状态块
    memset(&Ncb, sizeof(Ncb), 0);
    Ncb.ncb_command = NCBASTAT;
    Ncb.ncb_lana_num = adapterNum;
    strcpy((char*)Ncb.ncb_callname, "*");
    struct ASTAT
    {
   
   
        ADAPTER_STATUS adapt;
        NAME_BUFFER nameBuff[30];
    }adapter;
    memset(&adapter, sizeof(adapter), 0);
    Ncb.ncb_buffer = (unsigned char*)&adapter;
    Ncb.ncb_length = sizeof(adapter);
    if (Netbios(&Ncb) != 0)
        return false;

    char acMAC[32];
    sprintf(acMAC, "%02X-%02X-%02X-%02X-%02X-%02X",
        int(adapter.adapt.adapter_address[0]),
        int(adapter.adapt.adapter_address[1]),
        int(adapter.adapt.adapter_address[2]),
        int(adapter.adapt.adapter_address[3]),
        int(adapter.adapt.adapter_address[4]),
        int(adapter.adapt.adapter_address[5]));
    macOUT = acMAC;
    return true;
}

bool GetMacByNetBIOS(std::string& macOUT)
{
   
   
    // 取得网卡列表
    LANA_ENUM adapterList;
    NCB Ncb;
    memset(&Ncb, 0, sizeof(NCB));
    Ncb.ncb_command = NCBENUM;
    Ncb.ncb_buffer = (unsigned char*)&adapterList;
    Ncb.ncb_length = sizeof(adapterList);
    Netbios(&Ncb);

    // 取得MAC
    for (int i = 0; i < adapterList.length; ++i)
    {
   
   
        if (GetAdapterInfo(adapterList.lana[i], macOUT))
            return true;
    }

    return false;
}

int main(int argc, char *argv[])
{
   
   
    std::string refBuffer;

    GetMacByNetBIOS(refBuffer);
    std::cout << "Mac地址: " << refBuffer << std::endl;

    system("pause");
    return 0;
}

三种方式均可以输出系统的MAC地址,可根据自己的需求选择;

相关文章
|
8月前
|
缓存 网络协议
通过ARP协议实验,设置错误的IP和MAC地址的静态绑定项目,会使得两台主机之间无法通信,而删除该项目后可恢复通信,分析其原因。
通过ARP协议实验,设置错误的IP和MAC地址的静态绑定项目,会使得两台主机之间无法通信,而删除该项目后可恢复通信,分析其原因。
114 0
|
8月前
|
Python
python自带模块获取服务器主机名称、IP地址和mac地址
python自带模块获取服务器主机名称、IP地址和mac地址
87 1
|
11月前
|
Linux
Linux下修改网卡MAC地址
Linux下修改网卡MAC地址
169 0
|
Windows
全网首发:WINDOWS主机与MAC虚拟机文件访问的解决办法
全网首发:WINDOWS主机与MAC虚拟机文件访问的解决办法
146 0
全网首发:WINDOWS主机与MAC虚拟机文件访问的解决办法
|
Ubuntu Linux Perl
linux实用技巧:使用脚本获取活动网卡的mac地址
linux实用技巧:使用脚本获取活动网卡的mac地址
linux实用技巧:使用脚本获取活动网卡的mac地址
|
Windows
全网首发:WINDOWS主机与MAC虚拟机文件访问的解决办法
全网首发:WINDOWS主机与MAC虚拟机文件访问的解决办法
214 0
全网首发:WINDOWS主机与MAC虚拟机文件访问的解决办法
|
Windows
Windows 技术篇-网卡物理(MAC)地址查看方法
Windows 技术篇-网卡物理(MAC)地址查看方法
191 0
Windows 技术篇-网卡物理(MAC)地址查看方法
|
开发工具
Mac修改主机host地址
Mac修改主机host地址
163 0

热门文章

最新文章

相关产品

  • 云迁移中心