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地址的更多相关文章

  1. 获取客户端网卡MAC地址和IP地址实现JS代码

    获取客户端网卡MAC地址和IP地址实现JS代码 作者: 字体:[增加 减小] 类型:转载   获取客户端的一些信息,如IP和MAC,以结合身份验证,相信很多人都会这样做吧,我们这里用Javascrip ...

  2. C# 获取物理网卡Mac地址

    // <summary> /// 获取网卡物理地址 /// </summary> /// <returns></returns> public stat ...

  3. Python 获取 网卡 MAC 地址

    /*********************************************************************** * Python 获取 网卡 MAC 地址 * 说明: ...

  4. 获取CPU序列号、网卡MAC地址、硬盘序列号

    <pre name="code" class="csharp"> using System; using System.Collections; u ...

  5. 工作日记:C#获取操作系统、MAC地址、登录用户、网卡、物理内存信息

    /// <summary> /// 操作系统的登录用户名 /// </summary> /// <returns>系统的登录用户名</returns> ...

  6. 使用WinPcap获取网卡MAC地址

    关键字:WinPcap 网卡 MAC地址 作者:txw1958 在WpdPack_4_1_2\WpdPack\Examples-remote\PacketDriver\GetMacAddress\目录 ...

  7. Java/JSP获得客户端网卡MAC地址的三种方法解析

    java/jsp获得客户端(IE)网卡MAC地址的方法大概有三种. 1.通过命令方式,在客户端执行Ipconfig 等等.(java/jsp) 2.通过ActiveX的方法.(jsp) 3.通过向13 ...

  8. linux/Centos下查看和修改网卡Mac地址(ifconfig命令)

    本文转载自http://www.169it.com/article/14360294838474691537.html linux/Centos下查看网卡Mac地址,输入命令: #ifconfig - ...

  9. Centos下查看和修改网卡Mac地址

    linux/Centos下查看网卡Mac地址,输入命令: #ifconfig -a eth0 Link encap:Ethernet HWaddr 00:e4:56:2E:D8:20 00:e4:56 ...

  10. Java获取本机MAC地址[转]

    原文地址:https://www.cnblogs.com/hxsyl/p/3422191.html Java获取本机MAC地址   为什么写这个呢?因为前几天看见网上有采用windows命令获取局域网 ...

随机推荐

  1. Nginx--引用多配置文件

    在nginx.conf的http模块,include 指定某个目录下的*.conf user nginx; worker_processes auto; error_log /var/log/ngin ...

  2. 利用gost实现pptp转socks5或http代理

    利用gost实现pptp转socks5或http代理 以debian10为例 1.安装pptp服务器端 sudo apt-get install pptpd #debian系统 编辑/etc/pptp ...

  3. 【教程】步兵 cocos2dx 加密和混淆

    文章目录 摘要 引言 正文代码加密具体步骤代码加密具体步骤测试和配置阶段IPA 重签名操作步骤 总结 参考资料 摘要 本篇博客介绍了针对 iOS 应用中的 Lua 代码进行加密和混淆的相关技术.通过对 ...

  4. 《深入理解计算机系统》实验五 —— Perfom Lab

    本次实验是CSAPP的第5个实验,这次实验主要是让我们熟悉如何优化程序,如何写出更具有效率的代码.通过这次实验,我们可以更好的理解计算机的工作原理,在以后编写代码时,具有能结合软硬件思考的能力. @ ...

  5. node知识点及第三方模块

    1. 读文件内容 // 1. 通过模块的名字fs对模块进行引用 const fs = require('fs'); // 2. 通过模块内部的readFile读取文件内容 fs.readFile('. ...

  6. Linux系统CPU异常占用(minerd 、tplink等挖矿进程)

    转载请注明出处: 云服务器ECS(Linux) CPU使用率超过70%,严重时可达到100%,服务器响应越来越慢.  服务器中存在恶意minerd.tplink进程 该进程是服务器被入侵后,被恶意安装 ...

  7. npm, yarn和pnpm清理缓存

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  8. SpringBoot03:首页国际化

    页面国际化 有的时候,我们的网站会去涉及中英文甚至多语言的切换,这时候我们就需要学习国际化! 1.配置文件编写 首先在resources资源文件下新建一个i18n目录,存放国际化配置文件 新建一个lo ...

  9. Go-数组-实现队列

    package main import ( "errors" "fmt" ) // 队列 // 特征: // 1. 按照元素的添加顺序排序,并且容量固定 // ...

  10. [转帖]TiDB的使用限制

    https://docs.pingcap.com/zh/tidb/stable/tidb-limitations 本文会将详细描述 TiDB 中常见的使用限制,包括:标识符长度,最大支持的数据库.表. ...