一张网卡多个IP,获取首选IP的方法

1.思路

使用Windows的API函数来获取适配器信息,并遍历适配器列表,找到非回环类型的适配器,并且其IP地址不为0的适配器。然后,它会遍历该适配器的IP地址列表,找到与网关地址相匹配的IP地址,并将其作为本地IP地址返回。

主要步骤如下:

  1. 创建一个适配器信息的结构体实例。
  2. 获取适配器信息的大小,如果获取到的大小超过了初始分配的缓冲区大小,则重新分配更大的缓冲区。
  3. 获取适配器信息,并遍历适配器列表。
  4. 对于每个非回环类型且IP地址不为0的适配器,获取其网关地址,并将其转换为整数形式。
  5. 遍历该适配器的IP地址列表,对于每个IP地址,将其转换为整数形式,并与网关地址进行比较。
  6. 如果找到与网关地址匹配的IP地址,则将其作为本地IP地址返回。

2. api简介

DWORD GetAdaptersInfo(
  PIP_ADAPTER_INFO pAdapterInfo,
  PULONG           pOutBufLen
);

GetAdaptersInfo 是一个 Windows API 函数,用于获取系统中所有适配器的信息。它定义在 Windows 的 IPHlpApi.h 头文件中。
参数说明:

  • pAdapterInfo:一个指向 PIP_ADAPTER_INFO 结构体的指针,用于存储获取到的适配器信息。
  • pOutBufLen:一个指向变量的指针,用于传递 pAdapterInfo 缓冲区的大小。在调用函数之前,需要将其设置为 pAdapterInfo 缓冲区的大小。函数返回时,它将包含实际写入到 pAdapterInfo 缓冲区的字节数。

函数返回一个 DWORD 类型的错误码,如果函数执行成功,返回值为 ERROR_SUCCESS。

GetAdaptersInfo 函数通过遍历系统中的适配器列表,将每个适配器的信息填充到 pAdapterInfo 缓冲区中。通过多次调用该函数,可以获取系统中所有适配器的信息。

注意:这里将IP地址前三位与网关前三位相同的IP认为是首选IP地址

typedef struct _IP_ADAPTER_INFO {
    
    
    struct _IP_ADAPTER_INFO* Next;
    DWORD ComboIndex;
    char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
    char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
    UINT AddressLength;
    BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
    DWORD Index;
    UINT Type;
    UINT DhcpEnabled;
    PIP_ADDR_STRING CurrentIpAddress;
    IP_ADDR_STRING IpAddressList;
    IP_ADDR_STRING GatewayList;
    IP_ADDR_STRING DhcpServer;
    BOOL HaveWins;
    IP_ADDR_STRING PrimaryWinsServer;
    IP_ADDR_STRING SecondaryWinsServer;
    time_t LeaseObtained;
    time_t LeaseExpires;
} IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;

该结构体定义了适配器的信息,包括适配器的名称、描述、物理地址、IP 地址等。具体成员的含义如下:

  • Next:指向下一个适配器信息结构体的指针,用于遍历适配器列表。
  • ComboIndex:适配器的组合索引。
  • AdapterName:适配器的名称。
  • Description:适配器的描述。
  • AddressLength:适配器地址的长度。
  • Address:适配器的物理地址。
  • Index:适配器的索引。
  • Type:适配器的类型。
  • DhcpEnabled:指示适配器是否启用了 DHCP。
  • CurrentIpAddress:当前适配器的 IP 地址。
  • IpAddressList:适配器的 IP 地址列表。
  • GatewayList:适配器的网关地址列表。
  • DhcpServer:DHCP 服务器的 IP 地址。
  • HaveWins:指示适配器是否有 WINS 服务器。
  • PrimaryWinsServer:主要 WINS 服务器的 IP 地址。
  • SecondaryWinsServer:次要 WINS 服务器的 IP 地址。
  • LeaseObtained:租约获取时间。
  • LeaseExpires:租约到期时间。

通过遍历适配器列表,可以获取系统中所有适配器的信息,从而实现对网络连接的管理和配置。

2.代码

#include <string>
#include <iphlpapi.h>
#include <iostream>
#include <windows.h>
#include <mmsystem.h>

#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "ws2_32.lib")

using namespace std;

int AIUtils::GetLocalIp(std::string &ip) 
{
    
    
     PIP_ADAPTER_INFO adapterInfo;
     ULONG bufferSize = sizeof(IP_ADAPTER_INFO);
     adapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(new char[bufferSize]);

     if (GetAdaptersInfo(adapterInfo, &bufferSize) == ERROR_BUFFER_OVERFLOW) {
    
    
         delete[] reinterpret_cast<char*>(adapterInfo);
         adapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(new char[bufferSize]);
     }

     if (GetAdaptersInfo(adapterInfo, &bufferSize) == NO_ERROR) {
    
    
         IP_ADAPTER_INFO* adapter = adapterInfo;
         while (adapter) {
    
    
             if (adapter->Type != MIB_IF_TYPE_LOOPBACK && adapter->IpAddressList.IpAddress.String[0] != '0') {
    
    
                 std::string gateway_addr = adapter->GatewayList.IpAddress.String;
                 int a, b, c, d;
                 sscanf(gateway_addr.c_str(), "%d.%d.%d.%d", &a, &b, &c, &d);
                 IP_ADDR_STRING *addr = &adapter->IpAddressList;
                 while(addr) {
    
    
                     std::cout << "Primary IP address: " << addr->IpAddress.String << std::endl;
                     int a1, b1, c1, d1;
                     std::string ip_addr(addr->IpAddress.String);
                     sscanf(ip_addr.c_str(), "%d.%d.%d.%d", &a1, &b1, &c1, &d1);
                     if (a == a1 && b == b1 && c == c1) {
    
    
                         ip = ip_addr;
                         break;
                     }
                     addr = addr->Next;
                 }
                 break;
             }
             adapter = adapter->Next;
         }
     }

     if (adapterInfo) {
    
    
         delete[] reinterpret_cast<char*>(adapterInfo);
     }

     return 0;
}

猜你喜欢

转载自blog.csdn.net/wyw0000/article/details/131673156