English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Реализация получения информации о всех сетевых картах IP и MAC адресов на компьютере C++

На одном компьютере может быть не один сетевой адаптер, но у каждого адаптера есть только один MAC-адрес, а каждый адаптер может быть настроен с несколькими IP-адресами; например, в обычном ноутбуке есть два типа сетевых адаптеров: беспроводной адаптер и проводной адаптер (вход для сетевого кабеля); поэтому, чтобы получить информацию о всех IP и MAC-адресах сетевых адаптеров на этом компьютере, необходимо последовательно получить информацию о каждом адаптере и затем получить информацию о каждом из них; в Windows SDK информация о сетевых адаптерах хранится в структуре IP_ADAPTER_INFO, включая имя адаптера, описание адаптера, MAC-адрес адаптера, IP-адрес адаптера и т.д., основное описание которой приведено ниже:

typedef struct _IP_ADAPTER_INFO {
  struct _IP_ADAPTER_INFO* Next;//Pointer to the next adapter information in the list
  DWORD ComboIndex;//Reserved value
  char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];//Adapter name represented by ANSI string
  char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];//Adapter description represented by ANSI string
  UINT AddressLength;//Length of the adapter hardware address in bytes
  BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];//Hardware address represented as a BYTE array
  DWORD Index;//Adapter index
  UINT Type;//Adapter type, mainly the following types:
  /*
   *  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;//Specifies whether DHCP is enabled for this adapter
  PIP_ADDR_STRING CurrentIpAddress;//Reserved value
  IP_ADDR_STRING IpAddressList;//The IPv4 address list for this adapter
  IP_ADDR_STRING GatewayList;//The IPv4 gateway address list for this adapter
  IP_ADDR_STRING DhcpServer;//The IPv4 address list of the DHCP server for this adapter
  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; //вход в таблицу сетей. Этот значений соответствует параметру NTEContext в функциях AddIPAddress и DeleteIPAddress
} 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[])
{
  //переменная-пounter 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
    //Это означает, что переданного пространства для памяти недостаточно, и функция возвращает стSize, который указывает на необходимое пространство
    //Это также объясняет, почему 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;
{}

Вот и все, что я хотел рассказать вам о том, как получить все IP и MAC адреса всех сетевых карт компьютера на C++,希望大家多多支持呐喊教程~

Основной учебник
Рекомендуется для просмотра