C++獲得本機所有網卡的IP和MAC地址信息


轉載來自:https://www.cnblogs.com/fnlingnzb-learner/p/5942150.html

一台機器上可能不只有一個網卡,但每一個網卡只有一個MAC地址,而每一個網卡可能配置有多個IP地址;如平常的筆記本電腦中,就會有無線網卡和有線網卡(網線接口)兩種;

因此,如果要獲得本機所有網卡的IP和MAC地址信息,則必須順序獲得每個網卡,再依次獲取其信息等;在windows sdk中,IP_ADAPTER_INFO結構體存儲網卡信息,包括網卡名、網卡描述、網卡MAC地址、網卡IP等,該結構體的主要描述如下所示:

 

 

typedef struct _IP_ADAPTER_INFO {
  struct _IP_ADAPTER_INFO* Next;//指向鏈表中下一個適配器信息的指針
  DWORD ComboIndex;//預留值
  char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];//使用ANSI字符串表示的適配器名稱
  char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];//使用ANSI字符串表示的適配器描述
  UINT AddressLength;//適配器硬件地址以字節計算的長度
  BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];//硬件地址以BYTE數組所表示
  DWORD Index;//適配器索引
    UINT Type;//適配器類型,主要有以下幾種:
    /*
     *   MIB_IF_TYPE_OTHER     1
     *   MIB_IF_TYPE_ETHERNET     6
     *   MIB_IF_TYPE_TOKENRING     9
     *   MIB_IF_TYPE_FDDI     15
     *   MIB_IF_TYPE_PPP     23
     *   MIB_IF_TYPE_LOOPBACK      24
     *   MIB_IF_TYPE_SLIP      28
     */
  UINT DhcpEnabled;//指定這個適配器是否開啟DHCP
  PIP_ADDR_STRING CurrentIpAddress;//預留值
  IP_ADDR_STRING IpAddressList;//該適配器的IPv4地址鏈表
  IP_ADDR_STRING GatewayList;//該適配器的網關IPv4地址鏈表
  IP_ADDR_STRING DhcpServer;//該適配器的DHCP服務器的IPv4 地址鏈表
  BOOL HaveWins;
  IP_ADDR_STRING PrimaryWinsServer;
  IP_ADDR_STRING SecondaryWinsServer;
  time_t LeaseObtained;
  time_t LeaseExpires;
  } IP_ADAPTER_INFO,*PIP_ADAPTER_INFO;

 

由於可能有多個網卡,因此struct _IP_ADAPTER_INFO* Next字段為一個鏈表結構指針,由於一個網卡可能有多個IP,因此IP_ADDR_STRING字段應該也是一個鏈表結構,其信息如下所示:

typedef struct _IP_ADDR_STRING
{
    struct _IP_ADDR_STRING* Next;  //指向同類型節點,即下一個IP(如果有多IP的話)
    IP_ADDRESS_STRING IpAddress;  //IP地址信息
    IP_MASK_STRING IpMask; //IP子網掩碼
    DWORD Context;// 網絡表入口。這個值對應着AddIPAddredd和DeleteIPAddress函數中的NTEContext參數
} IP_ADDR_STRING;

綜上所述,用下圖來描述網卡的結構存儲信息,也許更明朗:

在基本了解以上信息后,就可以調用GetAdaptersInfo函數來獲取相關網卡信息了,其通用的代碼如下所示:

 

#include <WinSock2.h>
#include <Iphlpapi.h>
#include <iostream>
using namespace std;
#pragma comment(lib,"Iphlpapi.lib") //需要添加Iphlpapi.lib庫

int main(int argc, char* argv[])
{
    //PIP_ADAPTER_INFO結構體指針存儲本機網卡信息
    PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO();
    //得到結構體大小,用於GetAdaptersInfo參數
    unsigned long stSize = sizeof(IP_ADAPTER_INFO);
    //調用GetAdaptersInfo函數,填充pIpAdapterInfo指針變量;其中stSize參數既是一個輸入量也是一個輸出量
    int nRel = GetAdaptersInfo(pIpAdapterInfo,&stSize);
    //記錄網卡數量
    int netCardNum = 0;
    //記錄每張網卡上的IP地址數量
    int IPnumPerNetCard = 0;
    if (ERROR_BUFFER_OVERFLOW == nRel)
    {
        //如果函數返回的是ERROR_BUFFER_OVERFLOW
        //則說明GetAdaptersInfo參數傳遞的內存空間不夠,同時其傳出stSize,表示需要的空間大小
        //這也是說明為什么stSize既是一個輸入量也是一個輸出量
        //釋放原來的內存空間
        delete pIpAdapterInfo;
        //重新申請內存空間用來存儲所有網卡信息
        pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize];
        //再次調用GetAdaptersInfo函數,填充pIpAdapterInfo指針變量
        nRel=GetAdaptersInfo(pIpAdapterInfo,&stSize);    
    }
    if (ERROR_SUCCESS == nRel)
    {
        //輸出網卡信息
         //可能有多網卡,因此通過循環去判斷
    while (pIpAdapterInfo)
    {
        cout<<"網卡數量:"<<++netCardNum<<endl;
        cout<<"網卡名稱:"<<pIpAdapterInfo->AdapterName<<endl;
        cout<<"網卡描述:"<<pIpAdapterInfo->Description<<endl;
        switch(pIpAdapterInfo->Type)
        {
        case MIB_IF_TYPE_OTHER:
            cout<<"網卡類型:"<<"OTHER"<<endl;
            break;
        case MIB_IF_TYPE_ETHERNET:
            cout<<"網卡類型:"<<"ETHERNET"<<endl;
            break;
        case MIB_IF_TYPE_TOKENRING:
            cout<<"網卡類型:"<<"TOKENRING"<<endl;
            break;
        case MIB_IF_TYPE_FDDI:
            cout<<"網卡類型:"<<"FDDI"<<endl;
            break;
        case MIB_IF_TYPE_PPP:
            printf("PP\n");
            cout<<"網卡類型:"<<"PPP"<<endl;
            break;
        case MIB_IF_TYPE_LOOPBACK:
            cout<<"網卡類型:"<<"LOOPBACK"<<endl;
            break;
        case MIB_IF_TYPE_SLIP:
            cout<<"網卡類型:"<<"SLIP"<<endl;
            break;
        default:

            break;
        }
        cout<<"網卡MAC地址:";
        for (DWORD i = 0; i < pIpAdapterInfo->AddressLength; i++)
            if (i < pIpAdapterInfo->AddressLength-1)
            {
                printf("%02X-", pIpAdapterInfo->Address[i]);
            }
            else
            {
                printf("%02X\n", pIpAdapterInfo->Address[i]);
            }
            cout<<"網卡IP地址如下:"<<endl;
            //可能網卡有多IP,因此通過循環去判斷
            IP_ADDR_STRING *pIpAddrString =&(pIpAdapterInfo->IpAddressList);
            do 
            {
                cout<<"該網卡上的IP數量:"<<++IPnumPerNetCard<<endl;
                cout<<"IP 地址:"<<pIpAddrString->IpAddress.String<<endl;
                cout<<"子網地址:"<<pIpAddrString->IpMask.String<<endl;
                cout<<"網關地址:"<<pIpAdapterInfo->GatewayList.IpAddress.String<<endl;
                pIpAddrString=pIpAddrString->Next;
            } while (pIpAddrString);
            pIpAdapterInfo = pIpAdapterInfo->Next;
            cout<<"--------------------------------------------------------------------"<<endl;
    }
    
    }
    //釋放內存空間
    if (pIpAdapterInfo)
    {
        delete pIpAdapterInfo;
    }
 
    return 0;
}

執行結果:

 

第二種求IP地址的方法:

#include <winsock.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib") //用於鏈接到ws2_32.lib這個庫
void CheckIP(void)//CheckIP函數,用於獲取本機IP地址
{
 WORD wVersionRequested;//WORD類型變量,用於存放Winsock版本的值
 WSADATA wsaData;
 char name[255];//用於存放主機名
 PHOSTENT hostinfo;
 wVersionRequested=MAKEWORD(2,0);
 //調用MAKEWORD()函數獲得Winsock版本,用於加載Winsock庫
 if(WSAStartup(wVersionRequested,&wsaData) == 0)
 {
  //加載Winsock庫,如果WSAStartup()函數的返回值為0,說明加載成功
  if(gethostname(name,sizeof(name))==0)
  {
   if((hostinfo = gethostbyname(name) )!= NULL)
   {
    //如果獲得主機名成功的話,調用inet_ntoa()函數取得IP地址
    LPCSTR ip = inet_ntoa(*(struct in_addr *)*hostinfo->h_addr_list);
    printf("本機的IP地址是:%s\n",ip);//輸出ip地址
    printf("本機的名稱是:%s\n",name);
   }
  }
  WSACleanup();
 }
}
int main()
{
 CheckIP();//調用CheckIP()函數獲得並輸出IP地址
 return 0;

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM