自作ping

通信を行なうアプリケーションを作成すると、相手ホストが生きているかどうかを確認したくなるときがあります。 そのようなときには、pingのようにICMP Echoを投げるという方法で確認できます。 ソケットを使ってICMPを投げるプログラムをガリガリ書くことも可能ですが、IPHLPAPIでは、簡単にそれをするためにIcmpSendEcho()関数が用意されています。 ここでは、IcmpSendEcho()の使い方を説明します。

サンプルコード

IcmpSendEcho()を使ったサンプルコードを以下に示します。

他のIPHLPAPI関数と違う部分があるので注意してください。 まず、icmpapi.hをincludeしなくてはいけません。 次に、icmp.libにリンクしなくてはいけません。

しかも、icmpapi.hとicmp.libのある場所は環境に依存するようです。 私の環境では、「(Platform SDKが入っているフォルダ)\Misc\Icmp\」にicmpapi.hが入っていました。 また、ライブラリファイルのicmp.libは「(Platform SDKが入っているフォルダ)\Misc\Icmp\Lib\」にありました。


#include <stdio.h>

#include <winsock2.h>
#include <iphlpapi.h>
#include <icmpapi.h>

int
main()
{
 HANDLE hIcmp;
 char *SendData = "ICMP SEND DATA";
 LPVOID ReplyBuffer;
 DWORD dwRetVal;
 DWORD buflen;
 PICMP_ECHO_REPLY pIcmpEchoReply;

 hIcmp = IcmpCreateFile();

 buflen = sizeof(ICMP_ECHO_REPLY) + strlen(SendData) + 1;
 ReplyBuffer = (VOID*) malloc(buflen);
 if (ReplyBuffer == NULL) {
   return 1;
 }
 memset(ReplyBuffer, 0, buflen);
 pIcmpEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;

 dwRetVal = IcmpSendEcho(hIcmp, 
   inet_addr("127.0.0.1"), 
   SendData, strlen(SendData), 
   NULL, ReplyBuffer, 
   buflen,
   1000);
 if (dwRetVal != 0) {
   printf("Received %ld messages.\n", dwRetVal);
   printf("\n");
   printf("RTT: %d\n", pIcmpEchoReply->RoundTripTime);
   printf("Data Size: %d\n", pIcmpEchoReply->DataSize);
   printf("Message: %s\n", pIcmpEchoReply->Data);
 } else {
   printf("Call to IcmpSendEcho() failed.\n");
   printf("Error: %ld\n", GetLastError());
 }

 IcmpCloseHandle(hIcmp);

 return 0;
}

サンプルコード実行例

上記コードをコンパイルして出来たものを実行すると、以下のようになります。


C:> a.exe
Received 1 messages.

RTT: 0
Data Size: 14
Message: ICMP SEND DATA

ICMP_ECHO_REPLY 構造体

IcmpSendEcho()が利用している、ICMP_ECHO_REPLYは以下のように宣言されています。


typedef struct icmp_echo_reply {
  IPAddr Address;
  ULONG Status;
  ULONG RoundTripTime;
  USHORT DataSize;
  USHORT Reserved;
  PVOID Data;
  IP_OPTION_INFORMATION Options;
} ICMP_ECHO_REPLY, *PICMP_ECHO_REPLY;

Address IPアドレスです。
Status Echo Requestのステータスです。詳しくは、IPExport.hのIP_STATUSを参照してください。
RoundTripTime RTTです。msec単位です。
DataSize Replyデータのサイズです。(byte単位)
Reserved 使ってません。
Data ICMPのペイロード部分(データ部分)へのポインタです。
Options ICMP Replyのオプションです。IP_OPTION_INFORMATION形式です。

最後に

注意:IcmpSendEcho()はIPv4でしか使えません。 IPv6でICMPを送る場合には、Icmp6CreateFile()、Icmp6SendEcho2()を使ってください。

IPv6基礎検定

YouTubeチャンネルやってます!