ネットワークインターフェースの情報を取得する
ネットワークプログラミングを行なっていると、ネットワークインターフェースの数や、それぞれに関する情報を知りたくなってくると思います。 ここでは、それらの情報を取得する方法を説明します。
サンプルコード
ネットワークインターフェースのリストは、GetInterfaceInfo()関数を利用して取得できます。
#include <stdio.h>
#include <winsock2.h>
#include <iphlpapi.h>
int
main()
{
int i;
PIP_INTERFACE_INFO pInfo = NULL;
ULONG ulOutBufLen = 0;
DWORD dwRetVal = 0;
/* 変数 ulOutBufLen に必要なサイズを取得 */
if (GetInterfaceInfo(NULL, &ulOutBufLen)
== ERROR_INSUFFICIENT_BUFFER) {
pInfo = (IP_INTERFACE_INFO *) malloc (ulOutBufLen);
}
/* 実際にデータを取得する */
dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen);
if (dwRetVal == NO_ERROR ) {
printf("Number of Adapters: %ld\n\n", pInfo->NumAdapters);
for (i=0; i<pInfo->NumAdapters; i++) {
printf("Adapter Name: %ws\n", pInfo->Adapter[i].Name);
printf("Adapter Index: %ld\n", pInfo->Adapter[i].Index);
printf("\n");
}
} else {
printf("GetInterfaceInfo failed.\n");
LPVOID lpMsgBuf;
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dwRetVal,
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT), /* Default language */
(LPTSTR) &lpMsgBuf,
0,
NULL )) {
printf("Error: %s", lpMsgBuf);
}
LocalFree( lpMsgBuf );
}
return 0;
}
サンプルコード実行例
上記コードをコンパイルして出来たものを実行すると、以下のようになります。
C:> a.exe
Number of Adapters: 2
Adapter Name: \DEVICE\TCPIP_{22EXXC3D-F01D-4231-AE59-C23EXXXX6C66}
Adapter Index: 2
Adapter Name: \DEVICE\TCPIP_{4E7XX61B-836C-49AB-8B02-775BXXXX7352}
Adapter Index: 3
GetInterfaceInfo()が利用する構造体
上記サンプルを見ていると、やはりIP_INTERFACE_INFOの中身がどういうものか気になると思います。 GetInterfaceInfo()が使っているIP_INTERFACE_INFOは以下のように宣言されています。
typedef struct _IP_ADAPTER_INDEX_MAP {
ULONG Index;
WCHAR Name[MAX_ADAPTER_NAME];
} IP_ADAPTER_INDEX_MAP, *PIP_ADAPTER_INDEX_MAP;
typedef struct _IP_INTERFACE_INFO {
LONG NumAdapters;
IP_ADAPTER_INDEX_MAP Adapter[1];
} IP_INTERFACE_INFO, *PIP_INTERFACE_INFO;
ネットワークインターフェースのリストを取得する2
Adapter Nameで出てきた文字列は、ipconfigで出てくる名前とは違います。 これはこれで使い道があるのですが、このままではどれがどれだかわからないので、次は人間にわかりやすい名前を出す方法を説明したいと思います。
サンプルコード
インターフェースのDescriptionは、GetIfEntry()を使うと取得できます。 以下にGetIfEntry()を使う例を示します。
#include <stdio.h>
#include <winsock2.h>
#include <iphlpapi.h>
int
main()
{
DWORD i;
PMIB_IFTABLE ifTable;
MIB_IFROW MibIfRow;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
/*
* GetIfEntry()を使う前にエントリ数を
* 取得するためにGetIfTable()を使っています
*/
/* GetIfTable()で必要になるサイズを取得 */
if (GetIfTable(NULL, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
ifTable = (MIB_IFTABLE *) malloc (dwSize);
}
/* 実際にGetIfTable()を使う */
if ((dwRetVal = GetIfTable(ifTable, &dwSize, 0)) == NO_ERROR) {
if (ifTable->dwNumEntries > 0) {
printf("Number of Adapters: %ld\n\n", ifTable->dwNumEntries);
for (i=1; i<=ifTable->dwNumEntries; i++) {
MibIfRow.dwIndex = i;
if ((dwRetVal = GetIfEntry(&MibIfRow)) == NO_ERROR) {
printf("Description: %s\n", MibIfRow.bDescr);
}
}
}
} else {
printf("GetIfTable failed.\n");
LPVOID lpMsgBuf;
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dwRetVal,
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL )) {
printf("Error: %s", lpMsgBuf);
}
LocalFree( lpMsgBuf );
}
return 0;
}
サンプルコード実行例
上記コードをコンパイルして出来たものを実行すると、以下のようになります。
C:> a.exe
Number of Adapters: 3
Description: MS TCP Loopback Interface
Description: Intel (R) PRO/100 VE Network Connection
Description: 3Com Fast Ethernet Network Connection
GetIfTable()が利用する構造体
上記サンプル中で利用している、MIB_IFTABLEとMIB_IFROWは以下のように宣言されています。
typedef struct _MIB_IFROW {
WCHAR wszName[MAX_INTERFACE_NAME_LEN];
DWORD dwIndex;
DWORD dwType;
DWORD dwMtu;
DWORD dwSpeed;
DWORD dwPhysAddrLen;
BYTE bPhysAddr[MAXLEN_PHYSADDR];
DWORD dwAdminStatus;
DWORD dwOperStatus;
DWORD dwLastChange;
DWORD dwInOctets;
DWORD dwInUcastPkts;
DWORD dwInNUcastPkts;
DWORD dwInDiscards;
DWORD dwInErrors;
DWORD dwInUnknownProtos;
DWORD dwOutOctets;
DWORD dwOutUcastPkts;
DWORD dwOutNUcastPkts;
DWORD dwOutDiscards;
DWORD dwOutErrors;
DWORD dwOutQLen;
DWORD dwDescrLen;
BYTE bDescr[MAXLEN_IFDESCR];
} MIB_IFROW, *PMIB_IFROW;
typedef struct _MIB_IFTABLE {
DWORD dwNumEntries;
MIB_IFROW table[ANY_SIZE];
} MIB_IFTABLE, *PMIB_IFTABLE;