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)         {                          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 ;                          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);          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地址,可根据自己的需求选择;