首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

局域網電腦搜尋與 IP 取得 MAC 位址 C++ Builder 實作

     編輯:關於C++

前言

在區域網路開發中,常需列舉網路上所有電腦,並根據 IP 位址查詢對應的 MAC 位址。本文提供基於 Windows 網路 API(WNetEnumResource、gethostbyname)的 C++ Builder 完整實作碼,可直接整合至專案。

一、核心 API 介紹

WNetEnumResource - 列舉網路資源

  • 遞迴遍歷網路鄰居,取得伺服器名稱
  • 需包含 <winnetwk.h>,連結 mpr.lib

gethostbyname - 主機名解析 IP

  • Winsock API,將主機名解析為 IP 位址
  • 需包含 <winsock2.h>,連結 ws2_32.lib
  • 呼叫前需 WSAStartup,結束呼叫 WSACleanup

二、完整實作程式碼

表單建立事件:列舉網路電腦並顯示 IP

void __fastcall TForm1::FormCreate(TObject *Sender) {
    TStringList *netList = new TStringList();
    TListItem *newItem;
    
    ListView1->Items->Clear();
    Screen->Cursor = crHourGlass;
    
    // 遞迴列舉全域網路資源
    EnumNetResource(netList, NULL, RESOURCE_GLOBALNET, RESOURCETYPE_ANY);
    
    for (int i = 0; i < netList->Count; i++) {
        newItem = ListView1->Items->Add();
        newItem->Caption = netList->Strings[i];           // 電腦名稱
        newItem->SubItems->Add(GetHostIP(netList->Strings[i])); // 對應 IP
    }
    
    Screen->Cursor = crDefault;
    delete netList;
}

遞迴列舉網路資源函數

bool __fastcall TForm1::EnumNetResource(
    TStrings *rcList, LPNETRESOURCE lpNR, DWORD dwScope, DWORD dwType) {
    
    HANDLE hEnum = 0;
    DWORD dwResult = WNetOpenEnum(dwScope, dwType, 0, lpNR, &hEnum);
    if (dwResult != NO_ERROR) return false;
    
    bool bRet = true;
    DWORD dwEntries = 0xFFFFFFFF;  // 列舉所有項目
    NETRESOURCE NR[1024];
    DWORD dwBuffer = 1024 * sizeof(NETRESOURCE);
    
    while (true) {
        dwResult = WNetEnumResource(hEnum, &dwEntries, (LPVOID)NR, &dwBuffer);
        if (dwResult == ERROR_NO_MORE_ITEMS) break;
        if (dwResult != NO_ERROR) { bRet = false; break; }
        
        for (DWORD i = 0; i < dwEntries; i++) {
            // 只處理伺服器類型(電腦)
            if (NR[i].dwDisplayType == RESOURCEDISPLAYTYPE_SERVER) {
                char *p = NR[i].lpRemoteName;
                while (*p == '\\') p++;  // 跳過前導雙反斜線
                if (*p) rcList->Add(p);  // 加入電腦名稱
            }
            // 容器類型(如工作群組、網域)遞迴進入
            else if ((NR[i].dwUsage & RESOURCEUSAGE_CONTAINER) == RESOURCEUSAGE_CONTAINER) {
                bRet = EnumNetResource(rcList, &NR[i], dwScope, dwType);
                if (!bRet) break;
            }
        }
        if (!bRet) break;
    }
    
    WNetCloseEnum(hEnum);
    return bRet;
}

取得主機 IP 位址函數

AnsiString __fastcall TForm1::GetHostIP(AnsiString &host) {
    WSADATA wsaData;
    AnsiString IP;
    
    if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0) return "";
    
    try {
        // 若 host 為空,取得本機名稱
        if (host.IsEmpty()) {
            char hostname[128];
            if (gethostname(hostname, 128) != 0) return "";
            host = hostname;
        }
        
        struct hostent *hp = gethostbyname(host.c_str());
        if (WSAGetLastError() == WSAHOST_NOT_FOUND) {
            IP = "無法獲取";
        } else {
            // 取得第一個 IPv4 位址
            IP = inet_ntoa(*(struct in_addr*)hp->h_addr_list[0]);
        }
    } catch (...) {
        IP = "";
    }
    
    WSACleanup();
    return IP;
}

三、延伸應用:IP 反查 MAC 位址

上述程式碼僅解析 IP。若需進一步根據 IP 取得 MAC 位址,可使用 SendARP(IP Helper API):

#include <iptypes.h>
#include <iphlpapi.h>
// 連結 iphlpapi.lib

ULONG GetMacFromIP(AnsiString ipStr, BYTE mac[6]) {
    IPAddr destIp = inet_addr(ipStr.c_str());
    IPAddr srcIp = 0;  // 本機介面
    ULONG macAddr[2];
    ULONG physAddrLen = 6;
    
    DWORD ret = SendARP(destIp, srcIp, macAddr, &physAddrLen);
    if (ret == NO_ERROR && physAddrLen == 6) {
        memcpy(mac, macAddr, 6);
        return NO_ERROR;
    }
    return ret;
}

// 使用範例
BYTE mac[6];
if (GetMacFromIP("192.168.1.100", mac) == NO_ERROR) {
    AnsiString macStr;
    for (int i = 0; i < 6; i++) {
        if (i) macStr += "-";
        macStr += IntToHex(mac[i], 2);
    }
    ShowMessage("MAC: " + macStr);  // 格式如 00-1A-2B-3C-4D-5E
}

四、關鍵注意事項

  • 權限需求:列舉網路資源需具備網路存取權限
  • 防火牆影響:部分環境封鎖 NetBIOS/Winsock 流量導致列舉不全
  • IPv6 相容:gethostbyname 僅支援 IPv4,新專案建議改用 getaddrinfo
  • 效能考量:大型網域遞迴列舉耗時較久,建議放入背景執行緒並顯示進度
  • ARP 快取:SendARP 依賴本機 ARP 快取,目標必須近期有通訊紀錄
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved