C/C++獲取主機網(wǎng)卡MAC地址的三方法
MAC地址(Media Access Control address),又稱為物理地址或硬件地址,是網(wǎng)絡(luò)適配器(網(wǎng)卡)在制造時被分配的全球唯一的48位地址。這個地址是數(shù)據(jù)鏈路層(OSI模型的第二層)的一部分,用于在局域網(wǎng)(LAN)中唯一標識網(wǎng)絡(luò)設(shè)備。獲取網(wǎng)卡地址主要用于網(wǎng)絡(luò)標識和身份驗證的目的。MAC地址是一個唯一的硬件地址,通常由網(wǎng)卡的制造商在制造過程中分配。通過獲取MAC地址可以判斷當前主機的唯一性可以與IP地址綁定并實現(xiàn)網(wǎng)絡(luò)準入控制。
在Windows平臺下獲取MAC地址的方式有很多,獲取MAC地址的常見方式包括使用操作系統(tǒng)提供的網(wǎng)絡(luò)API(如Windows的GetAdaptersAddresses和GetAdaptersInfo),NetBIOS API,系統(tǒng)命令(如ipconfig /all),ARP緩存表查詢,第三方庫(如WinPcap或Libpcap),以及在編程語言中使用網(wǎng)絡(luò)庫。
首先第一種獲取方法封裝GetMacByGetAdaptersAddresses
函數(shù),該功能的實現(xiàn)通過調(diào)用系統(tǒng)中的GetAdaptersAddresses
獲取計算機的MAC地址。
該函數(shù)首先分配內(nèi)存來存儲適配器信息,然后調(diào)用 GetAdaptersAddresses 函數(shù)獲取適配器信息。如果內(nèi)存不足,它會重新分配足夠的內(nèi)存并再次調(diào)用該函數(shù)。接著,它遍歷返回的適配器信息,找到第一個物理地址長度為6的適配器,然后將其MAC地址以格式化字符串的形式存儲在傳入的 macOUT 變量中。最后,釋放分配的內(nèi)存,并返回一個布爾值。
#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
函數(shù),通過調(diào)用系統(tǒng)的GetAdaptersInfo
獲取計算機的主網(wǎng)卡的MAC地址。函數(shù)首先分配內(nèi)存來存儲適配器信息,然后調(diào)用GetAdaptersInfo
獲取適配器信息。如果內(nèi)存不足,它會重新分配足夠的內(nèi)存并再次調(diào)用該函數(shù)。接著,它遍歷返回的適配器信息,找到第一個類型為以太網(wǎng)且物理地址長度為6的適配器,然后將其MAC地址以格式化字符串的形式存儲在傳入的macOUT
變量中。最后,釋放分配的內(nèi)存,并返回一個布爾值。
#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) { // 確保是以太網(wǎng) 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
函數(shù),其使用NetBIOS API
獲取指定適配器號(adapterNum)
的MAC地址。函數(shù)首先通過NCBRESET
命令重置指定網(wǎng)卡以便進行查詢。接著,使用NCBASTAT
命令獲取接口卡的狀態(tài)塊,其中包含了適配器的物理地址。如果NetBIOS
調(diào)用成功,將適配器的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)); // 重置網(wǎng)卡 以便我們可以查詢 Ncb.ncb_command = NCBRESET; Ncb.ncb_lana_num = adapterNum; if (Netbios(&Ncb) != NRC_GOODRET) return false; // 準備取得接口卡的狀態(tài)塊 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) { // 取得網(wǎng)卡列表 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; }
三種方式均可以輸出系統(tǒng)的MAC地址,可根據(jù)自己的需求選擇;
以上就是C/C++獲取主機網(wǎng)卡MAC地址的三方法的詳細內(nèi)容,更多關(guān)于C/C++ 獲取MAC地址的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Linux網(wǎng)絡(luò)編程之基于UDP實現(xiàn)可靠的文件傳輸示例
這篇文章主要介紹了Linux網(wǎng)絡(luò)編程之基于UDP實現(xiàn)可靠的文件傳輸示例,是很實用的技巧,需要的朋友可以參考下2014-08-08