首页 > 编程语言 >C/C++ 获取主机网卡MAC地址

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

时间:2023-11-19 09:33:43浏览次数:31  
标签:-% int adapter C++ 网卡 MAC Ncb 02X

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

标签:-%,int,adapter,C++,网卡,MAC,Ncb,02X
From: https://www.cnblogs.com/LyShark/p/17840833.html

相关文章

  • C++默认参数实现原理分析
    简介定义C++默认参数指的是当函数调用中省略了实参时自动使用的一个值。写法如下:voidfoo(inta=1){}voidfoo(inta,intb=1,intc=1){}默认参数有两个规则,规则一:从第一个出现默认参数的参数开始,后面的参数必须也指定默认参数voidfoo(inta=1,intb,intc=1......
  • Code-C++-字符串分割
    Code-C++-字符串分割转自【C++中string如何实现字符串分割函数split()——4种方法-CSDNApp】http://t.csdnimg.cn/8iWb7stringstreamgetline()stringfind()substr()ccharstrtok()strtok_r()regex_token_iterator<>getline()voidStringsplit(stringstr,const......
  • c++线程专题
    逐步更新中~~~,参考书籍《C++并发编程实战(第2版)》,不照搬书,只写理解感悟。引入头文件#include<thread>线程启动std::threadt(my_func);若需等待线程执行完毕,才继续之后的代码,用joinif(t.joinable()){t.join();}若不等待,可以分离出去(分离出去的线程被称为守护......
  • C++ Primer学习笔记——第十二章
    第十二章动态内存前言在此之前,我们使用的程序中对象都有着严格定义的生存期:全局对象,在程序启动时分配,在程序结束是销毁。局部自动对象,当进入定义所在程序时创建,在离开块时销毁。局部static对象,在第一次使用前分配,在程序结束时销毁。显然这存在限制,为此C++支持动态分配对......
  • C++ 观察者模式实现
    观察者模式主体(被观察者)通知一个或多个观察者状态改变/数据更新/事件发生。描述C++实现观察者模式有几个要点:观察者都有一个共同的抽象基类Listener,定义了一个纯虚接口OnNotified(),主体调用该接口通知观察者每个观察者ConcreteListener继承自抽象基类Listener,并实现......
  • 开启linux网卡
    查看目录,如果有ifcfg-eth0,ifcfg-ens33之类的,表示有网卡但不确定是否开启,如果使用的vmware,且有桌面的化,可以用鼠标点一点就可以开启网络[root@bogonnetwork-scripts]#pwd/etc/sysconfig/network-scripts[root@bogonnetwork-scripts]#lsifcfg-eth0ifdown-ipppifdown-r......
  • go语言window|mac|linux下交叉编译其他平台的软件包
    go语言window|mac|linux下交叉编译其他平台的软件包注意:go1.17发现直接使用set是不起作用的,必须要使用goenv-w来设置一、设置编译环境,需要发布哪个平台Window下1、设置Linux编译环境SETCGO_ENABLED=0setGOARCH=amd64setGOOS=linux2、设置Mac编译环境goenv......
  • C/C++ 运用VMI接口查询系统信息
    WindowsManagementInstrumentation(WMI)是一种用于管理和监视Windows操作系统的框架。它为开发人员、系统管理员和自动化工具提供了一种标准的接口,通过这个接口,可以获取有关计算机系统硬件、操作系统和应用程序的信息,以及对系统进行管理和控制的能力。WMI允许通过编程方式查询系......
  • L1-6 吉老师的回归 (15 分)(C/C++)
    输入样例1:51L1-1isaqiandaoproblem.L1-2isso...easy.L1-3isEasy.L1-4isqianDao.Wow,suchL1-5,soeasy.输出样例1:L1-4isqianDao.输入样例2:54L1-1isa-qiandaoproblem.L1-2issoeasy.L1-3isEasy.L1-4isqianDao.Wow,suchL1-5,so!!easy.输出样例......
  • 给机顶盒编译无线网卡驱动
    给机顶盒编译无线网卡驱动需要一些特定的步骤。以下是一般的步骤:确定机顶盒的无线网卡型号:在机顶盒的背面或底部通常会找到无线网卡的型号信息。需要确定型号,以便下载和安装正确的驱动程序。下载无线网卡驱动程序:根据机顶盒的型号和操作系统的版本,从相应的网站或官方网站下载无线......