C/C++获取主机网卡MAC地址的三方法

 更新时间:2023年11月19日 09:56:18   作者:微软技术分享  
MAC地址(Media Access Control address),又称为物理地址或硬件地址,是网络适配器(网卡)在制造时被分配的全球唯一的48位地址,通过获取MAC地址可以判断当前主机的唯一性可以与IP地址绑定并实现网络准入控制,本文给大家介绍了使用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 <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地址,可根据自己的需求选择;

以上就是C/C++获取主机网卡MAC地址的三方法的详细内容,更多关于C/C++ 获取MAC地址的资料请关注脚本之家其它相关文章!

相关文章

  • 对称矩阵的压缩储存讲解

    对称矩阵的压缩储存讲解

    今天小编就为大家分享一篇关于对称矩阵的压缩储存讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • Linux网络编程之基于UDP实现可靠的文件传输示例

    Linux网络编程之基于UDP实现可靠的文件传输示例

    这篇文章主要介绍了Linux网络编程之基于UDP实现可靠的文件传输示例,是很实用的技巧,需要的朋友可以参考下
    2014-08-08
  • 汇编语言rep movsd 的使用详解

    汇编语言rep movsd 的使用详解

    rep movsd 每次ecx!=0便执行movsd ,然后ecx=ecx-1 movsd移动ds:[si] 到es:[di],在32位汇编下可以用esi代替si,edi代替di
    2013-09-09
  • 一篇文章教你自己动手实现C语言库函数

    一篇文章教你自己动手实现C语言库函数

    这篇文章主要介绍了C语言库函数的相关资料,小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-09-09
  • c语言排序之归并排序(递归和非递归)

    c语言排序之归并排序(递归和非递归)

    这篇文章主要介绍了 c语言排序之归并排序(递归和非递归),归并就是把两个或多个序列合并,本文主要介绍二路归并,下文相关资料需要的小伙伴可以参考一下
    2022-04-04
  • C++ STL中一些常用算法总结

    C++ STL中一些常用算法总结

    都说STL是数据容器与算法的高度组合,在前面的文章中我们介绍了常见的几种容器,vector、list、map、deque等,今天我们再来介绍下STL中常用的一些算法,需要的朋友可以参考下
    2024-02-02
  • 实例代码分析c++动态分配

    实例代码分析c++动态分配

    这篇文章主要介绍了c++动态分配的的相关资料,文中代码简单易懂,方便大家更好的学习参考,感兴趣的朋友可以了解下
    2020-06-06
  • C++ 类模板与成员函数模板示例解析

    C++ 类模板与成员函数模板示例解析

    这篇文章主要为大家介绍了C++ 类模板与成员函数模板示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • 深入聊聊C语言中的Const关键字

    深入聊聊C语言中的Const关键字

    关键字const用来定义只读变量,被const定义的变量它的值是不允许改变的,即不允许给它重新赋值,即使是赋相同的值也不可以,下面这篇文章主要给大家介绍了关于C语言中Const关键字的相关资料,需要的朋友可以参考下
    2022-02-02
  • 关于C++中引用和指针的区别详解

    关于C++中引用和指针的区别详解

    这篇文章主要介绍了关于C++中引用和指针的区别详解,
    2023-07-07

最新评论