澳门威尼斯人官网得到MAC地址

Windows平台下用C++代码取得机器的MAC地址并不是一件简单直接的事情。到目前为止,作者尚未发现有任何一个通用的100%的适用于所有Windows平台的方法可以稳定的取得MAC地址。而有些应用(比如MMORPG)则需要稳定的得到机器的MAC地址,解决方案往往是通过多种方法依次使用来提高成功率。

实例代码:

//linux
int GetLocalMacAddr(char *szMac,int *pnMacLen)
{
  int   sock;   
  struct   sockaddr_in   sin;   
  struct   sockaddr   sa;   
  struct   ifreq   ifr;   
  unsigned   char   mac[6];   

  sock=socket(AF_INET,SOCK_DGRAM,0);   
  if (sock==-1)   
  {   
    perror("socket");   
    return 1;   
  }   

  strncpy(ifr.ifr_name,"eth0",sizeof(ifr.ifr_name));   
  ifr.ifr_name[IFNAMSIZ-1]   =   0;   

  memset(mac,0,sizeof(mac));   
  if (ioctl(sock,SIOCGIFHWADDR,&ifr)< 0)   
  {   
    perror("ioctl");   
    return 2;   
  }   

  memcpy(&sa,&ifr.ifr_addr,sizeof(sin));   
  memcpy(mac,sa.sa_data,sizeof(mac));   
  char curmacstr[64];
  memset(curmacstr,0,sizeof(curmacstr));
  //sprintf(curmacstr,"%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
  sprintf(curmacstr,"%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
  strcpy(szMac,curmacstr);
  return 0;

}

// windows
int CUtil::GetOtherMacAddr(char *szIP,char *szBuf,int *pnBufLen)
{
    HRESULT hr;
    IPAddr  ipAddr;
    ULONG   pulMac[2];
    ULONG   ulLen;
    char strMacAddr[100]={0};
    ipAddr = inet_addr (szIP);
    memset (pulMac, 0xff, sizeof (pulMac));
    ulLen = 6;
    hr = SendARP (ipAddr, 0, pulMac, &ulLen);
    if(hr!=NO_ERROR)
        return 1;

    unsigned char * mac_addr=(unsigned char*)pulMac;
    //sprintf(strMacAddr,"%02X-%02X-%02X-%02X-%02X-%02X",mac_addr[0],mac_addr[1],
    //    mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]);
    sprintf(strMacAddr,"%02X:%02X:%02X:%02X:%02X:%02X",mac_addr[0],mac_addr[1],
        mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]);
    if ( *pnBufLen <= (int)strlen(strMacAddr) )
        return 2;
    strcpy(szBuf,strMacAddr);
    *pnBufLen = strlen(szBuf);

    return 0;
}

int CUtil::GetLocalMacAddr(char *szMac,int *pnMacLen,char *szIP /*=NULL */)
{
    //如果指定了IP,则直接按IP获取MAC
    //否则,需要先获取本机名称,再获取IP,再获取MAC
    if ( szIP != NULL )
        return GetOtherMacAddr(szIP,szMac,pnMacLen);

    char szHostName[256] = {0};
    int nRet = gethostname(szHostName,256);
    if ( nRet == SOCKET_ERROR )
        return 1;

    //获取本机名称
    struct hostent* hHost = gethostbyname(szHostName);
    if ( hHost == NULL ||  hHost->h_addr_list[0] == NULL )
        return 2;

    //获取IP地址
    memset(szHostName,0,256);
    strcpy(szHostName,inet_ntoa(*(struct in_addr *)hHost->h_addr_list[0]));

    //获取MAC
    return  GetOtherMacAddr(szHostName,szMac,pnMacLen);
}
//该片段来自于http://outofmemory.cn
  • 以下方法只会返回多网卡的第一个MAC地址。
  • 网上有很多文章和源码来解决该问题,大多不全或有问题。本篇所有方法均经过整理调试,可直接使用。
  • 作者也不喜欢满篇帖代码,本篇贴代码是方便直接使用,请读者谅解。
#include <Windows.h>
#include <iphlpapi.h>
#include <list>
#include <string>
#pragma comment(lib, "Iphlpapi.lib")

std::list<std::string> GetMACs()
{
 std::list<std::string> lst;

 ULONG ulSize = 0;
 ::GetAdaptersInfo(nullptr, &ulSize);

 if (ulSize == 0) return lst;

 PIP_ADAPTER_INFO pInfo = (PIP_ADAPTER_INFO)malloc(ulSize);
 if (::GetAdaptersInfo(pInfo, &ulSize) != ERROR_SUCCESS)
 {
  free(pInfo);
  return lst;
 }

 PIP_ADAPTER_INFO pNext = pInfo;
 while (pNext != nullptr)
 {
  std::string mac;
  char tmp[10];
  for (int i = 0; i < (int)pNext->AddressLength; i++)
  {
   sprintf_s(tmp, "%02X-", pNext->Address[i]);
   mac += tmp;
  }
  if (!mac.empty())
  {
   mac.pop_back();
   lst.emplace_back(std::move(mac));
  }
  pNext = pNext->Next;
 }

 free(pInfo);

 return lst;
}

int main()
{
 GetMACs();
    return 0;
}

    下面奉上几种常用的方法:

  


方法一:通过NetBIOS.aspx)

  
 [Netbios.aspx) is
not supported on Windows Vista, Windows Server 2008, and subsequent
versions of the operating system]

#include <windows.h>

#pragma comment(lib, “Netapi32.lib”)

namespace

{

bool GetAdapterInfo(int adapterNum, std::string& macOUT)

{

NCB.aspx) Ncb;

memset(&Ncb, 0, sizeof(Ncb));

Ncb.ncb_command = NCBRESET; // 重置网卡,以便我们可以查询

Ncb.ncb_lana_num = adapterNum;

if
(Netbios.aspx)(&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.aspx)(&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.aspx)(&Ncb);

// 取得MAC

for (int i = 0; i < adapterList.length; ++i)

{

if (GetAdapterInfo(adapterList.lana[i], macOUT))

return true;

}

return false;

}

参考:

取得系统中网卡MAC地址的三种方法


方法二:通过对控制台ipconfig /all命令重定向

#include <Windows.h>

#include <boost\regex.hpp>

namespace

{

#if 0

/// @brief 采用字符串查找来提取MAC地址

/// @remark
该方法有很大局限性,并不是所有OS返回的MAC地址前导字符串都是

///     “Physical Address. . . . . . . . . : “

bool ParseMac(const std::string& str, std::string& macOUT)

{

static const std::string beginMarkOfMAC(“Physical Address. . . . . . .
. . : “);

static const std::string endMarkOfMAC(“\r\n”);

size_t begin = str.find(beginMarkOfMAC);

if(begin != std::string::npos)

{

begin += beginMarkOfMAC.size();

size_t end = str.find(endMarkOfMAC, begin);

if(end != std::string::npos)

{

macOUT = str.substr(begin, end – begin – 1);

return true;

}

}

return false;

}

#else

/// @brief
采用boost::regex来提取MAC

bool ParseMac(const std::string& str, std::string& macOUT)

{

const static boost::regex expression(

“([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})”, 

boost::regex::perl | boost::regex::icase);

boost::cmatch what; 

if(boost::regex_search(str.c_str(), what, expression)) 

{

macOUT = what[1] + “-” + what[2] + “-” + what[3] + “-” +
what[4] + “-” + what[5] + “-” + what[6];

return true;

}

return false;

}

#endif

}

bool GetMacByCmd(std::string& macOUT)

{

bool ret = false;

//初始化返回MAC地址缓冲区

SECURITY_ATTRIBUTES sa; 

sa.nLength = sizeof(SECURITY_ATTRIBUTES); 

sa.lpSecurityDescriptor = NULL; 

sa.bInheritHandle = TRUE; 

//创建管道

HANDLE hReadPipe,hWritePipe;

if(CreatePipe.aspx)(&hReadPipe,
&hWritePipe, &sa, 0) == TRUE)

{

//控制命令行窗口信息

STARTUPINFO si; 

//返回进程信息

PROCESS_INFORMATION pi;

si.cb = sizeof(STARTUPINFO); 

GetStartupInfo(&si); 

si.hStdError = hWritePipe; 

si.hStdOutput = hWritePipe; 

si.wShowWindow = SW_HIDE; //隐藏命令行窗口

si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

//创建获取命令行进程

if (CreateProcess(NULL, “ipconfig /all”, NULL, NULL, TRUE, 0, NULL,
NULL, &si, &pi) == TRUE) 

WaitForSingleObject(pi.hProcess, 3000); //
设置超时时间,防止Vista、Win7等操作系统卡死

unsigned long count;

CloseHandle(hWritePipe);

std::string strBuffer(1024 * 10, ‘\0’); // 准备足够大的缓冲区

if(ReadFile(hReadPipe, const_cast<char*>(strBuffer.data()),
strBuffer.size() – 1, &count, 0) == TRUE)

{

strBuffer.resize(strBuffer.find_first_of(‘\0′)); //
截掉缓冲区后面多余的’\0’

ret = ParseMac(strBuffer, macOUT);//提取MAC地址串

}

CloseHandle(pi.hThread); 

CloseHandle(pi.hProcess); 

}

CloseHandle(hWritePipe); // VS2010下调试,此处会有“An invalid handle
was specified”的中断,直接运行正常,原因未知。VS2008上正常。

CloseHandle(hReadPipe);

}

return ret;

}

参考:

Boost编译

VC获取MAC地址的4种方法


方法三:通过SNMP(简单网络访问协议)

#include <snmp.h>

#pragma comment(lib, “snmpapi.lib”)

#pragma comment(lib, “Ws2_32.lib”)

bool GetMacBySNMP(std::string& macOUT)

{

bool ret = false;

WSADATA WinsockData;

if (WSAStartup(MAKEWORD(2, 0), &WinsockData) != 0) 

return false;

// Load the SNMP dll and get the addresses of the functions necessary

const HINSTANCE m_dll = LoadLibrary(“inetmib1.dll”);

if (m_dll < (HINSTANCE) HINSTANCE_ERROR)

return false;

const PFNSNMPEXTENSIONINIT f_SnmpExtensionInit =
(PFNSNMPEXTENSIONINIT) GetProcAddress(m_dll, “SnmpExtensionInit”);

const PFNSNMPEXTENSIONINITEX f_SnmpExtensionInitEx =
(PFNSNMPEXTENSIONINITEX) GetProcAddress(m_dll,
“SnmpExtensionInitEx”);

const PFNSNMPEXTENSIONQUERY f_SnmpExtensionQuery =
(PFNSNMPEXTENSIONQUERY) GetProcAddress(m_dll, “SnmpExtensionQuery”);

const PFNSNMPEXTENSIONTRAP f_SnmpExtensionTrap =
(PFNSNMPEXTENSIONTRAP) GetProcAddress(m_dll, “SnmpExtensionTrap”);

HANDLE pollForTrapEvent;

AsnObjectIdentifier supportedView;

f_SnmpExtensionInit(GetTickCount(), &pollForTrapEvent,
&supportedView);

// Initialize the variable list to be retrieved by
f_SnmpExtensionQuery

const AsnObjectIdentifier MIB_NULL = { 0, 0 };

RFC1157VarBind varBind[2];

varBind[0].name = MIB_NULL;

varBind[1].name = MIB_NULL;

RFC1157VarBindList varBindList;

varBindList.list = varBind;

UINT OID_ifEntryType[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };

UINT OID_ifEntryNum[] = { 1, 3, 6, 1, 2, 1, 2, 1 };

UINT OID_ipMACEntAddr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6 };

AsnObjectIdentifier MIB_ifMACEntAddr = { sizeof(OID_ipMACEntAddr) /
sizeof(UINT), OID_ipMACEntAddr };

AsnObjectIdentifier MIB_ifEntryType = { sizeof(OID_ifEntryType) /
sizeof(UINT), OID_ifEntryType };

AsnObjectIdentifier MIB_ifEntryNum = { sizeof(OID_ifEntryNum) /
sizeof(UINT), OID_ifEntryNum };

// Copy in the OID to find the number of entries in the Inteface table

varBindList.len = 1;        // Only retrieving one item

SnmpUtilOidCpy(&varBind[0].name, &MIB_ifEntryNum);

AsnInteger errorStatus;

AsnInteger errorIndex;

f_SnmpExtensionQuery(ASN_RFC1157_GETNEXTREQUEST, &varBindList,
&errorStatus, &errorIndex);

varBindList.len = 2;

// Copy in the OID of ifType, the type of interface

SnmpUtilOidCpy(&varBind[0].name, &MIB_ifEntryType);

// Copy in the OID of ifPhysAddress, the address

SnmpUtilOidCpy(&varBind[1].name, &MIB_ifMACEntAddr);

for(int j = 0; j < varBind[0].value.asnValue.number; j++)

{

// Submit the query.  Responses will be loaded into varBindList.

// We can expect this call to succeed a # of times corresponding to
the # of adapters reported to be in the system

if(f_SnmpExtensionQuery(ASN_RFC1157_GETNEXTREQUEST, &varBindList,
&errorStatus, &errorIndex) == FALSE)

continue;

// Confirm that the proper type has been returned

if(SnmpUtilOidNCmp(&varBind[0].name, &MIB_ifEntryType,
MIB_ifEntryType.idLength) != 0)

continue;

// Type 6 describes ethernet interfaces

if(varBind[0].value.asnValue.number != 6) 

continue;

// Confirm that we have an address here

if(SnmpUtilOidNCmp(&varBind[1].name, &MIB_ifMACEntAddr,
MIB_ifMACEntAddr.idLength) != 0)

continue;

if(varBind[1].value.asnValue.address.stream == NULL)

continue;

// Ignore all dial-up networking adapters

if ((varBind[1].value.asnValue.address.stream[0] == 0x44)

&& (varBind[1].value.asnValue.address.stream[1] == 0x45)

&& (varBind[1].value.asnValue.address.stream[2] == 0x53)

&& (varBind[1].value.asnValue.address.stream[3] == 0x54)

&& (varBind[1].value.asnValue.address.stream[4] == 0x00)) 

continue;

// Ignore NULL addresses returned by other network interfaces

if ((varBind[1].value.asnValue.address.stream[0] == 0x00)

&& (varBind[1].value.asnValue.address.stream[1] == 0x00)

&& (varBind[1].value.asnValue.address.stream[2] == 0x00)

&& (varBind[1].value.asnValue.address.stream[3] == 0x00)

&& (varBind[1].value.asnValue.address.stream[4] == 0x00)

&& (varBind[1].value.asnValue.address.stream[5] == 0x00)) 

continue;

char buf[32];

sprintf(buf, “%02X-%02X-%02X-%02X-%02X-%02X”,

varBind[1].value.asnValue.address.stream[0],

varBind[1].value.asnValue.address.stream[1],

varBind[1].value.asnValue.address.stream[2],

varBind[1].value.asnValue.address.stream[3],

varBind[1].value.asnValue.address.stream[4],

varBind[1].value.asnValue.address.stream[5]);

macOUT = buf;

ret = true;

break;

}

// Free the bindings

SnmpUtilVarBindFree(&varBind[0]);

SnmpUtilVarBindFree(&varBind[1]);

return ret;

}

参考:

SNMP
Provider.aspx)

SNMP
Functions.aspx)

Install and Enable SNMP Service in Windows XP, Vista and
2003

Visual
C++通过snmp获取mac地址


方法四:通过GetAdaptersInfo.aspx)函数(适用于Windows
2000及以上版本)

#include <winsock2.h>

#include <iphlpapi.h>

#pragma comment(lib, “IPHLPAPI.lib”)

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;

// Make an initial call to GetAdaptersInfo to get the necessary size
into the ulOutBufLen variable

if(GetAdaptersInfo.aspx)(pAdapterInfo,
&ulOutBufLen) == ERROR_BUFFER_OVERFLOW) 

{

free(pAdapterInfo);

pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);

if (pAdapterInfo == NULL) 

return false;

}

if(GetAdaptersInfo.aspx)(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;

}

参考:


方法五:通过GetAdaptersAddresses.aspx)函数(适用于Windows
XP及以上版本)

#include <winsock2.h>

#include <iphlpapi.h>

#pragma comment(lib, “IPHLPAPI.lib”)

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;

// Make an initial call to GetAdaptersAddresses to get the necessary
size into the ulOutBufLen variable

if(GetAdaptersAddresses.aspx)(AF_UNSPEC,
0, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW)

{

free(pAddresses);

pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);

if (pAddresses == NULL) 

return false;

}

if(GetAdaptersAddresses.aspx)(AF_UNSPEC,
0, NULL, pAddresses, &outBufLen) == NO_ERROR)

{

// If successful, output some information from the data we received

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;

}

发表评论

电子邮件地址不会被公开。 必填项已用*标注