问题描述
我使用以下示例程序编写了一个程序: https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersinfo
然而,我面临的问题是,当我列出适配器描述和适配器 IP 地址时,所有 IPv4 地址(包括 VirtualBox 地址)都会显示出来。我们对 Intel(R) Dual Band Wireless-AC 7265 IP 地址感兴趣。
在执行程序时,下面是适配器描述,显示的 IP 地址:
ComboIndex: 17
Adapter Name: {E783F44-FB13-4D75-962E-BB5DE229F1B1}
Adapter Desc: VirtualBox Host-Only Ethernet Adapter
Adapter Addr: 0A-00-28-00-00-13
Index: 19
Type: Ethernet
IP Address: 192.168.36.1
IP Mask: 255.255.255.0
Gateway: 0.0.0.0
***
DHCP Enabled: No
Have Wins: No
ComboIndex: 5
Adapter Name: {3A58A814-B840-4951-9302-6D2fdb404FF3}
Adapter Desc: Intel(R) Dual Band Wireless-AC 7265
Adapter Addr: C8-24-58-50-47-32
Index: 5
Type: UnkNown type 71
IP Address: 192.168.0.106
IP Mask: 255.255.255.0
Gateway: 192.168.0.1
***
DHCP Enabled: Yes
DHCP Server: 192.168.0.1
Lease Obtained: Tue Jan 19 17:17:51 2021
Lease Expires: Fri Apr 17 00:14:00 1970
Have Wins: No
ComboIndex: 18
Adapter Name: {FB92F018-6F10-47D3-96D6-010DAF3DDEB8}
Adapter Desc: Microsoft Wi-Fi Direct Virtual Adapter
Adapter Addr: C8-24-58-50-46-34
Index: 18
Type: UnkNown type 71
IP Address: 0.0.0.0
IP Mask: 0.0.0.0
Gateway: 0.0.0.0
***
DHCP Enabled: Yes
DHCP Server:
Lease Obtained: Thu Jan 1 05:30:00 1970
Lease Expires: Thu Jan 1 05:30:00 1970
Have Wins: No
ComboIndex: 12
Adapter Name: {7CD8BFA9-ACEB-48CB-A241-D3CA9342EEF4}
Adapter Desc: Microsoft Wi-Fi Direct Virtual Adapter #2
Adapter Addr: CA-22-58-51-45-35
Index: 12
Type: UnkNown type 71
IP Address: 0.0.0.0
IP Mask: 0.0.0.0
Gateway: 0.0.0.0
***
DHCP Enabled: Yes
DHCP Server:
Lease Obtained: Thu Jan 1 05:30:00 1970
Lease Expires: Invalid Argument to _localtime32_s
Have Wins: No
因此,为了仅读取系统的 IP 地址,我修改了程序以搜索除“Microsoft”或“Virtual”之外的字符串(以消除适配器描述)。
这适用于我的系统。但我不相信这是获取机器 IP 地址的最佳方式。
关于如何修改逻辑以获取执行此程序的任何系统的 IP 地址的任何建议,非常感谢!
程序如下:
#include <vector>
#include <iostream>
#include <string.h>
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib,"IPHLPAPI.lib")
#define MALLOC(x) HeapAlloc(GetProcessHeap(),(x))
#define FREE(x) HeapFree(GetProcessHeap(),(x))
using namespace std;
/* Note: Could also use malloc() and free() */
string getMachineIPAddr()
{
/* Declare and initialize variables */
vector<string> adapterName;
vector<string> adapterDesc;
vector<string> adapterIpAddr;
int count = 0;
// It is possible for an adapter to have multiple
// IPv4 addresses,gateways,and secondary WINS servers
// assigned to the adapter.
//
// Note that this sample code only prints out the
// first entry for the IP address/mask,and gateway,and
// the primary and secondary WINS server for each adapter.
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
UINT i;
/* variables used to print DHCP time info */
struct tm newtime;
char buffer[32];
errno_t error;
string err_str = "Err: Exiting function!";
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO*)MALLOC(sizeof(IP_ADAPTER_INFO));
if (pAdapterInfo == NULL) {
printf("Error allocating memory needed to call GetAdaptersinfo\n");
return err_str;
}
// Make an initial call to GetAdaptersInfo to get
// the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo(pAdapterInfo,&ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
FREE(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO*)MALLOC(ulOutBufLen);
if (pAdapterInfo == NULL) {
printf("Error allocating memory needed to call GetAdaptersinfo\n");
return err_str;
}
}
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo,&ulOutBufLen)) == NO_ERROR) {
pAdapter = pAdapterInfo;
while (pAdapter) {
printf("\tComboIndex: \t%d\n",pAdapter->ComboIndex);
printf("\tAdapter Name: \t%s\n",pAdapter->AdapterName);
printf("\tAdapter Desc: \t%s\n",pAdapter->Description);
printf("\tAdapter Addr: \t");
adapterName.push_back(pAdapter->AdapterName);
adapterDesc.push_back(pAdapter->Description);
adapterIpAddr.push_back(pAdapter->IpAddressList.IpAddress.String);
for (i = 0; i < pAdapter->AddressLength; i++) {
if (i == (pAdapter->AddressLength - 1))
printf("%.2X\n",(int)pAdapter->Address[i]);
else
printf("%.2X-",(int)pAdapter->Address[i]);
}
printf("\tIndex: \t%d\n",pAdapter->Index);
printf("\tType: \t");
switch (pAdapter->Type) {
case MIB_IF_TYPE_OTHER:
printf("Other\n");
break;
case MIB_IF_TYPE_ETHERNET:
printf("Ethernet\n");
break;
case MIB_IF_TYPE_TOKENRING:
printf("Token Ring\n");
break;
case MIB_IF_TYPE_FDDI:
printf("FDDI\n");
break;
case MIB_IF_TYPE_PPP:
printf("PPP\n");
break;
case MIB_IF_TYPE_LOOPBACK:
printf("Lookback\n");
break;
case MIB_IF_TYPE_SLIP:
printf("Slip\n");
break;
default:
printf("UnkNown type %ld\n",pAdapter->Type);
break;
}
printf("\tIP Address: \t%s\n",pAdapter->IpAddressList.IpAddress.String);
printf("\tIP Mask: \t%s\n",pAdapter->IpAddressList.IpMask.String);
printf("\tGateway: \t%s\n",pAdapter->GatewayList.IpAddress.String);
printf("\t***\n");
if (pAdapter->DhcpEnabled) {
printf("\tDHCP Enabled: Yes\n");
printf("\t DHCP Server: \t%s\n",pAdapter->Dhcpserver.IpAddress.String);
printf("\t Lease Obtained: ");
/* display local time */
error = _localtime32_s(&newtime,(__time32_t*)&pAdapter->LeaSEObtained);
if (error)
printf("Invalid Argument to _localtime32_s\n");
else {
// Convert to an ASCII representation
error = asctime_s(buffer,32,&newtime);
if (error)
printf("Invalid Argument to asctime_s\n");
else
/* asctime_s returns the string terminated by \n\0 */
printf("%s",buffer);
}
printf("\t Lease Expires: ");
error = _localtime32_s(&newtime,(__time32_t*)&pAdapter->LeaseExpires);
if (error)
printf("Invalid Argument to _localtime32_s\n");
else {
// Convert to an ASCII representation
error = asctime_s(buffer,buffer);
}
}
else
printf("\tDHCP Enabled: No\n");
if (pAdapter->HaveWins) {
printf("\tHave Wins: Yes\n");
printf("\t Primary Wins Server: %s\n",pAdapter->PrimaryWinsServer.IpAddress.String);
printf("\t Secondary Wins Server: %s\n",pAdapter->SecondaryWinsServer.IpAddress.String);
}
else
printf("\tHave Wins: No\n");
pAdapter = pAdapter->Next;
printf("\n");
}
}
else {
printf("GetAdaptersInfo Failed with error: %d\n",dwRetVal);
}
// THIS IS CODE TO ELIMINATE ADAPTERS WITH 'MICROSOFT' OR 'VIRTUAL'
// IN THE ADAPTER DESCRIPTIONS
vector<string>::iterator it = adapterDesc.begin();
vector<string>::iterator it2 = adapterIpAddr.begin();
string compareStr1 = "Microsoft";
string compareStr2 = "Virtual";
string outAdapterDesc = "";
string outAdapterIPAddr = "";
for (it = adapterDesc.begin(),it2 = adapterIpAddr.begin(); it != adapterDesc.end(); it++,it2++)
{
printf("*it: %s\n",it->c_str());
printf("*it2: %s\n",it2->c_str());
size_t found = it->find("Microsoft");
size_t found2 = it->find("Virtual");
if ((found == string::npos) || (found2 == string::npos))
{
outAdapterDesc = *it;
outAdapterIPAddr = *it2;
}
}
printf("outAdapterDesc: %s\n",outAdapterDesc.c_str());
printf("outAdapterIPAddr: %s\n",outAdapterIPAddr.c_str());
if (pAdapterInfo)
FREE(pAdapterInfo);
return outAdapterIPAddr;
}
int __cdecl main()
{
string machineIPAddr = getMachineIPAddr();
cout << "machineIPAddr: " << getMachineIPAddr() << endl;
}
解决方法
调用 GetBestRoute
以获取到相关 IP 地址的路由,并检查生成的 MIB_IPFORWARDROW::dwForwardIfIndex
接口索引。谷歌在 8.8.8.8 的 DNS 是一个合理的选择。你实际上并没有连接,只是检查如果你尝试会发生什么。您的 VirtualBox 界面将无法达到 8.8.8.8,但 VPN 可以。