1. アイデア
Windows API 関数を使用してアダプタ情報を取得し、アダプタ リストを検索して IP アドレスが 0 ではない非ループバック アダプタを見つけます。次に、そのアダプターの IP アドレスのリストを調べて、ゲートウェイ アドレスに一致する IP アドレスを見つけて、それをローカル IP アドレスとして返します。
主な手順は次のとおりです。
- アダプター情報の構造体インスタンスを作成します。
- アダプタ情報のサイズを取得し、取得したサイズが最初に割り当てられたバッファサイズを超える場合は、より大きなバッファを再割り当てします。
- アダプター情報を取得し、アダプターのリストを調べます。
- IP アドレスが 0 ではない非ループバック アダプタごとに、そのゲートウェイ アドレスを取得し、それを整数に変換します。
- このアダプターの IP アドレスのリストを反復処理し、IP アドレスごとにそれを整数形式に変換し、ゲートウェイ アドレスと比較します。
- ゲートウェイ アドレスと一致する 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 アドレスの最初の 3 桁とゲートウェイの最初の 3 桁が同じ 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: アダプターのコンボ インデックス。
- AdaptorName: アダプターの名前。
- 説明: アダプターの説明。
- AddressLength: アダプターのアドレスの長さ。
- アドレス: アダプターの物理アドレス。
- インデックス: アダプターのインデックス。
- タイプ: アダプターのタイプ。
- 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;
}