Visual studio 2015でPingプログラムを試しています。 以下のurlを参照しています。コンパイルが通り実行しまいた。host名でのpingは成功しました。ただし、IPアドレスでは失敗します。理由はDNSやHOSTSから名前が引けてないからです。実施には通信機器などDNS登録がないものも多々あるのでこれでは使いもになりません。

http://www.winsock2.org/samples/Ch05/PingI/pingi.c

iaDest.s_addr = inet_addr(argv[1]);
if (iaDest.s_addr == INADDR_NONE)
pHost = gethostbyname(argv[1]);
else
pHost = gethostbyaddr((const char *)&iaDest, sizeof(struct in_addr), AF_INET);
if (pHost == NULL){
fprintf(stderr, "\n%s not found\n", argv[1]);
WSACleanup();
FreeLibrary(hndlIcmp);
return;
}

// 動作状況をユーザーに表示
printf("\nPinging %s [%s]", pHost->h_name,
inet_ntoa((*(LPIN_ADDR)pHost->h_addr_list[0])));

// IPアドレスをコピー
dwAddress = (DWORD *)(*pHost->h_addr_list);

一番簡単な方法はdwAddressに直接argv[1]を入れればいいtおもっています。単なる代入式(=)ではうまくいきませんでした。DWORDでCastしてもだめでした。

どなたか、解決方法をご教授いただけますか?

回答の条件
  • 1人1回まで
  • 13歳以上
  • 登録:2016/10/27 23:09:49
  • 終了:2016/11/03 23:10:03

回答(1件)

id:soqans No.1

soqans回答回数8ベストアンサー獲得回数32016/10/28 20:17:47

ポイント100pt

直接IPアドレスを指定する場合は少し変更する必要がありそうです。質問の中で指摘があるとおりIPアドレスから逆引きできない場合に失敗する状態ですのでその場合は指定されたIPを直接使ってpingを発行するようにすればよいと思います。

具体的には修正後のコードを書いてみますと


struct in_addr iaDest,iaBuf; // インターネットアドレス構造体(バッファ部分追加)

iaDest.s_addr = inet_addr(argv[1]);
if (iaDest.s_addr == INADDR_NONE)
pHost = gethostbyname(argv[1]);
else
pHost = gethostbyaddr((const char *)&iaDest,
sizeof(struct in_addr), AF_INET);
if (pHost == NULL)
{
if(iaDest.s_addr == INADDR_NONE)
{
fprintf(stderr, "\n%s not found\n", argv[1]);
WSACleanup();
FreeLibrary(hndlIcmp);
return;
}
else{
// アドレスをバッファにコピー
memcpy(&iaBuf,&iaDest,sizeof(struct in_addr));
dwAddress = (DWORD *)(&iaBuf);

// 動作状況をユーザーに表示
printf("\nPinging [%s]",inet_ntoa(iaBuf));
}
}
else
{
// 動作状況をユーザーに表示
printf("\nPinging %s [%s]", pHost->h_name,
inet_ntoa((*(LPIN_ADDR)pHost->h_addr_list[0])));

// IPアドレスをコピー
dwAddress = (DWORD *)(*pHost->h_addr_list);
}


説明を書いておきますと引数としてIPv4形式のアドレス文字列("192.168.0.1"など)を与えるとinet_addr関数がそれを32bitの値に変換します。値に変換した場合はgethostbyaddr関数で逆引きをします。このとき元のプログラムでは失敗したときは終了するようになっていますがこの修正版ではその場合は逆引き失敗を無視してdwAddressにiaDestをコピーしたiaBuf(関数の先頭でiaDestの宣言に追加する)のポインタを格納するようになっています。

これはIcmpSendEcho関数の第2引数として渡さなければならないのがin_addr構造体そのもので、in_addr構造体が32bit値であることを利用して同じ32bit値のDWORDのポインタを参照する、という形で処理されているからです。(おそらくh_addr_listからのデータの受け取りを考えているのでしょうが…)

動作を追ってみればわかりますが逆引きに失敗したときはいったんin_addr構造体であるiaBufのポインタを格納してIcmpSendEcho関数の引数としてポインタを参照することで事実上in_addr構造体そのものを参照する、という動きになります。

DWORD *を使っているあたりが少し読みづらいポイントかもしれません。

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません