Windows/Linux获取Mac地址和CPU序列号实现
UUID(Universally Unique Identifier)即通用唯一標識符,是指在一臺機器上生成的數字,保證在全球范圍的唯一性。可用的開源庫如libuuid,可參考https://blog.csdn.net/fengbingchun/article/details/94590406。
UDID(Unique Device Identifier)即設備唯一標識符。一般可通過獲取設備的MAC地址+設備的CPU序列號作為設備的唯一標識符。
MAC地址(Media Access Control Address),直譯為媒體訪問控制地址,也稱為局域網地址(LAN Address),以太網地址(Ethernet Address)或物理地址(Physical Address),它是一個用來確認網絡設備位置的地址。在OSI模型中,第三層網絡層負責IP地址,第二層數據鏈路層則負責MAC地址。MAC地址用于在網絡中唯一標示一個網卡,一臺設備若有一或多個網卡,則每個網卡都需要并會有一個唯一的MAC地址。
MAC地址共48位(6個字節),以十六進制表示。第1Bit為廣播地址(0)/群播地址(1),第2Bit為廣域地址(0)/區域地址(1)。前3~24位由IEEE決定如何分配給每一家制造商,且不重復,后24位由實際生產該網絡設備的廠商自行指定且不重復。
通過命令查看MAC地址:
(1). Windows:打開命令提示符(cmd.exe),運行ipconfig/all命令,執行結果如下所示:如果計算機上有多個網絡設備(無論物理或虛擬),則會有多組信息及MAC地址,需辨識相應的設備。
(2). Linux:第一種方法運行ifconfig命令;第二種方法運行ip link show命令,執行結果如下所示:eth0為第一塊物理網卡,HWaddr 2c:fd:a1:bc:1f:44就是MAC地址,lo為本地回環地址。
修改MAC地址:網卡MAC地址可以通過Windows設備管理員或其他工具修改。對于某些手機、平板電腦設備來說,其MAC地址/產品序號均由廠方連同銷售或保修時的客戶資料一并記錄在案,而有關的MAC地址也不可通過常規手段來修改。
注:以上MAC地址內容主要來自?維基百科
CPU都有一個唯一的ID號,稱CPUID,即CPU序列號,是在制造CPU的時候,由廠家置入到CPU內部的。但是近年的Intel CPU不再區分同一批次中各個CPU的序列號,這樣就有可能兩臺電腦獲得的CPU序列號是一樣的。
通過命令查看CPU序列號:
(1). Windows:打開命令提示符,運行wmic cpu get processorid命令,執行結果如下圖所示:
(2). Linux:第一種方法運行dmidecode -t 4 | grep ID命令;第二種方法運行cpuid -r命令,執行結果如下圖所示:
以下是代碼段通過C++獲取Mac地址和CPU序列號的實現:
namespace {#ifdef __linux__ // reference: https://stackoverflow.com/questions/6491566/getting-the-machine-serial-number-and-cpu-id-using-c-c-in-linux inline void native_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {// ecx is often an input as well as an outputasm volatile("cpuid": "=a" (*eax),"=b" (*ebx),"=c" (*ecx),"=d" (*edx): "0" (*eax), "2" (*ecx)); } #endif} // namespaceint get_mac_and_cpuid() {// get mac #ifdef _MSC_VER// reference: https://stackoverflow.com/questions/13646621/how-to-get-mac-address-in-windows-with-cPIP_ADAPTER_INFO AdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));if (AdapterInfo == nullptr) {fprintf(stderr, "fail to malloc\n");return -1;}DWORD dwBufLen = sizeof(IP_ADAPTER_INFO);std::unique_ptr<char[]> mac_addr(new char[18]);// Make an initial call to GetAdaptersInfo to get the necessary size into the dwBufLen variableif (GetAdaptersInfo(AdapterInfo, &dwBufLen) == ERROR_BUFFER_OVERFLOW) {free(AdapterInfo);AdapterInfo = (IP_ADAPTER_INFO *)malloc(dwBufLen);if (AdapterInfo == nullptr) {fprintf(stderr, "fail to malloc\n");return -1;}}if (GetAdaptersInfo(AdapterInfo, &dwBufLen) == NO_ERROR) {for (PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo; pAdapterInfo != nullptr; pAdapterInfo = pAdapterInfo->Next) {// technically should look at pAdapterInfo->AddressLength and not assume it is 6.if (pAdapterInfo->AddressLength != 6) continue;if (pAdapterInfo->Type != MIB_IF_TYPE_ETHERNET) continue;sprintf(mac_addr.get(), "%02X:%02X:%02X:%02X:%02X:%02X",pAdapterInfo->Address[0], pAdapterInfo->Address[1],pAdapterInfo->Address[2], pAdapterInfo->Address[3],pAdapterInfo->Address[4], pAdapterInfo->Address[5]);fprintf(stdout, "mac address: %s\n", mac_addr.get());break;}}free(AdapterInfo); #else// reference: https://stackoverflow.com/questions/1779715/how-to-get-mac-address-of-your-machine-using-a-c-program/35242525int sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0) {fprintf(stderr, "fail to socket: %d\n", sock);return -1;};struct ifconf ifc;char buf[1024];int success = 0;ifc.ifc_len = sizeof(buf);ifc.ifc_buf = buf;if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) {fprintf(stderr, "fail to ioctl: SIOCGIFCONF\n");return -1;}struct ifreq* it = ifc.ifc_req;const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));struct ifreq ifr;for (; it != end; ++it) {strcpy(ifr.ifr_name, it->ifr_name);if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {if (!(ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopbackif (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {success = 1;break;}}} else { fprintf(stderr, "fail to ioctl: SIOCGIFFLAGS\n");return -1;}}unsigned char mac_address[6];if (success) memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);fprintf(stdout, "mac address: %02X:%02X:%02X:%02X:%02X:%02X\n", mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5]); #endif// Capture vendor stringchar vendor[0x20];memset(vendor, 0, sizeof(vendor));// get cpid #ifdef _MSC_VER// reference: https://docs.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex?view=vs-2019std::array<int, 4> cpui;// Calling __cpuid with 0x0 as the function_id argument gets the number of the highest valid function ID__cpuid(cpui.data(), 0);int nIds_ = cpui[0];std::vector<std::array<int, 4>> data_; for (int i = 0; i <= nIds_; ++i) {__cpuidex(cpui.data(), i, 0);data_.push_back(cpui);fprintf(stdout, "%08X-%08X-%08X-%08X\n", cpui[0], cpui[1], cpui[2], cpui[3]);}*reinterpret_cast<int*>(vendor) = data_[0][1];*reinterpret_cast<int*>(vendor + 4) = data_[0][3];*reinterpret_cast<int*>(vendor + 8) = data_[0][2];fprintf(stdout, "vendor: %s\n", vendor); // GenuineIntel or AuthenticAMD or otherfprintf(stdout, "vendor serialnumber: %08X%08X\n", data_[1][3], data_[1][0]); #elseunsigned eax, ebx, ecx, edx;eax = 0; // processor info and feature bitsnative_cpuid(&eax, &ebx, &ecx, &edx);fprintf(stdout, "%d, %d, %d, %d\n", eax, ebx, ecx, edx);*reinterpret_cast<int*>(vendor) = ebx;*reinterpret_cast<int*>(vendor + 4) = edx;*reinterpret_cast<int*>(vendor + 8) = ecx;fprintf(stdout, "vendor: %s\n", vendor); // GenuineIntel or AuthenticAMD or othereax = 1; // processor serial numbernative_cpuid(&eax, &ebx, &ecx, &edx);// see the CPUID Wikipedia article on which models return the serial number in which registersprintf("vendor serialnumber: %08X%08X\n", edx, eax); #endifreturn 0; }Windows下執行結果如下所示:與命令行執行結果相同
Linux上執行結果如下圖所示:與命令行執行結果相同
GitHub:https://github.com//fengbingchun/Messy_Test
總結
以上是生活随笔為你收集整理的Windows/Linux获取Mac地址和CPU序列号实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VisualStudio2012的序列号
- 下一篇: linux 开机画面