VS2012 C++ 中通過GetAdaptersInfo獲取多網卡,多IP地址信息

一臺機器上可能不只有一個網卡,但每一個網卡只有一個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;//適配器類型
   
  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 "stdafx.h"

#include "winsock.h"
#include "stdio.h"
#include <IPHlpApi.h>
#pragma comment(lib,"Iphlpapi.lib")

int _tmain(int argc, _TCHAR* argv[])
{    
    PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO();// PIP_ADAPTER_INFO結構體指針存儲本機網卡信息
    unsigned long stSize = sizeof(IP_ADAPTER_INFO);// 得到結構體大小,用於GetAdaptersInfo參數
    int netCardNum = 0;// 記錄網卡數量
    int IPnumPerNetCard = 0; // 記錄每張網卡上的IP地址數量

     //調用GetAdaptersInfo函數,填充pIpAdapterInfo指針變量;其中stSize參數既是一個輸入量也是一個輸出量
    int nRel = GetAdaptersInfo(pIpAdapterInfo,&stSize);
    if (ERROR_BUFFER_OVERFLOW == nRel)
    {
        /*如果函數返回的是ERROR_BUFFER_OVERFLOW
          則說明GetAdaptersInfo參數傳遞的內存空間不夠,同時其傳出stSize,表示需要的空間大小
          這也是說明爲什麼stSize既是一個輸入量也是一個輸出量
          釋放原來的內存空間*/
        delete pIpAdapterInfo;       
        pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize]; // 重新申請內存空間用來存儲所有網卡信息
        nRel=GetAdaptersInfo(pIpAdapterInfo,&stSize);//再次調用GetAdaptersInfo函數,填充pIpAdapterInfo指針變量  
    }
    if (ERROR_SUCCESS == nRel)
    {
        while (pIpAdapterInfo)
        {
            printf("\n┌────────────Num.%d────────────┐\n",++netCardNum);
            printf("│Name:%s\n",pIpAdapterInfo->AdapterName);
            printf("│Desc:%s\n",pIpAdapterInfo->Description);
            switch(pIpAdapterInfo->Type)
            {
            case MIB_IF_TYPE_OTHER:
                printf("│Type:OTHER\n");
                break;
            case MIB_IF_TYPE_ETHERNET:
                printf("│Type:ETHERNET\n");
                break;
            case MIB_IF_TYPE_TOKENRING:
                printf("│Type:TOKENRING\n");
                break;
            case MIB_IF_TYPE_FDDI:
                printf("│Type:FDDI\n");
                break;
            case MIB_IF_TYPE_PPP:
                printf("│Type:PPP\n");
                break;
            case MIB_IF_TYPE_LOOPBACK:
                printf("│Type:LOOPBACK\n");
                break;
            case MIB_IF_TYPE_SLIP:
                printf("│Type:SLIP\n");
                break;
            default:
                break;
            }

            printf("│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]);
                }
            }
            //可能網卡有多IP,因此通過循環去判斷
            IP_ADDR_STRING *pIpAddrString =&(pIpAdapterInfo->IpAddressList);
            do
            {
                printf("│IP:%s\n",pIpAddrString->IpAddress.String);
                printf("│MASK:%s\n",pIpAddrString->IpMask.String);
                printf("│Gate:%s\n",pIpAdapterInfo->GatewayList.IpAddress.String);
                pIpAddrString=pIpAddrString->Next;
            } while (pIpAddrString);
            pIpAdapterInfo = pIpAdapterInfo->Next;
            printf("└──────────────────────────┘\n");
        }
    
    }
    //釋放內存空間
    if (pIpAdapterInfo)
    {
        delete pIpAdapterInfo;
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章