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


    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 
    #include 
    #include 
    #include 
    
    #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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

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

    #define _CRT_SECURE_NO_WARNINGS
    #define _WIN32_DCOM
    #define _CRT_NONSTDC_NO_DEPRECATE
    
    #include 
    #include 
    #include 
    #include 
    
    #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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

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

    #include 
    #include 
    #include 
    #include 
    
    #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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

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

  • 相关阅读:
    图解LeetCode——754. 到达终点数字(难度:中等)
    Signoff Criteria --- ocv applied and results
    STM32G030F6P6点灯闪烁
    推荐系统[八]算法实践总结V0:腾讯音乐全民K歌推荐系统架构及粗排设计
    C# Onnx DIS高精度图像二类分割
    GBASE 8A v953报错集锦38--orato8a 指定 parallel 参数全表导出时前几分钟无数 据写入
    科技与环卫的结合,是智慧公厕厂家的使命
    第一章《初学者问题大集合》第7节:编写第一个Java程序
    React 全栈体系(七)
    C/C++-内存
  • 原文地址:https://blog.csdn.net/lyshark_csdn/article/details/134487138