.NET TIPS

pingパケットを送受信するには?[2.0のみ、C#、VB]

デジタルアドバンテージ 一色 政彦
2006/03/03

 .NET Framework 2.0では、新たにPingクラス(System.Net.NetworkInformation名前空間)が追加されている。Pingクラスを使用すれば、TCP/IPネットワーク上の特定のコンピュータへICMP(Internet Control Message Protocol)エコー・メッセージ(いわゆるpingパケット)を送信し、その応答を受信することで、リモート・コンピュータへのパケットの到達性を確認したり、ネットワーク上での応答速度を測定したりできる。本稿では、このPingクラスの基本的な利用方法を解説する。

 Pingクラスによるpingパケットの送信とその応答受信の方法には、次の2種類が存在する。

  • 同期通信(=基本的に、応答が返ってくるまで制御が戻らない)
  • 非同期通信(=送信し終わると即座に制御が戻る)

 本稿ではこのうち、同期通信でpingパケットを送信する方法を紹介する。非同期で送信する方法については、MSDNの「Ping.SendAsyncメソッド」の説明を参照してほしい。

同期通信でpingを送信するには?

 同期通信でpingパケットを送信するには、Pingクラスのインスタンスを作成し、Sendメソッドを呼び出せばよい。

 このSendメソッドにはいくつかのオーバーロードがあるが(詳しくはMSDNのページを参照してほしい)、ここでは(最もシンプルに使える)IPアドレスやホスト名を文字列でパラメータに指定できるバージョンのSendメソッドを使ったサンプル・プログラムを示す。

using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      string address = "dapc89";
      // IPアドレスを指定することも可能
      //string address = "192.168.0.102";

      try
      {
        // 送信先のホスト名とIPアドレスを表示する
        IPHostEntry ipInfo = Dns.GetHostEntry(address);
        string hostName = ipInfo.HostName;
        string ipAddress = ipInfo.AddressList[0].ToString();
        Console.WriteLine(
          "Pinging {0} [{1}] with 32 bytes of data:\n",
          hostName, ipAddress);

        // pingを実際に送信する
        Ping sender = new Ping();
        for (int i = 0; i < 4; i++)
        {
          PingReply reply = sender.Send(address);
          if (reply.Status == IPStatus.Success)
          {
            Console.WriteLine(
              "Reply from {0}: bytes={1} time={2}ms TTL={3}",
              reply.Address,
              reply.Buffer.Length,
              reply.RoundtripTime,
              reply.Options.Ttl);   // Time to live
          }
          else
          {
            Console.WriteLine(reply.Status);
          }

          // ping送信の間隔を少し空ける
          if (i < 3)
          {
            Thread.Sleep(1000);
          }
        }

        Console.WriteLine("\nPing.Send Completed.");

      }
      catch (SocketException ex)
      {
        string errorMessage = string.Format(
          "ホスト {0} が見つかりませんでした。\n"
          " → 理由:{1}",
          address, ex.Message);
        Console.WriteLine(errorMessage);
      }
      catch (PingException ex)
      {
        string errorMessage = string.Format(
          "{0} へのpingパケット送信に失敗しました。\n"
          " → 理由:{1}",
          address, ex.InnerException.Message);
        Console.WriteLine(errorMessage);
      }
    }
  }
}
Imports System.Net
Imports System.Net.NetworkInformation
Imports System.Net.Sockets
Imports System.Threading

Module Module1

  Sub Main()

    Dim address As String = "dapc89"
    ' IPアドレスを指定することも可能
    'string address = "192.168.0.102";

    Try
      ' 送信先のホスト名とIPアドレスを表示する
      Dim ipInfo As IPHostEntry = Dns.GetHostEntry(address)
      Dim hostName As String = ipInfo.HostName
      Dim ipAddress As String = ipInfo.AddressList(0).ToString()
      Console.WriteLine( _
        "Pinging {0} [{1}] with 32 bytes of data:" & vbLf, _
        hostName, ipAddress)

      ' pingを実際に送信する

      Dim sender As Ping = New Ping()
      For i As Integer = 0 To 4 - 1 Step i + 1
        Dim reply As PingReply = sender.Send(address)
        If reply.Status = IPStatus.Success Then
          Console.WriteLine( _
            "Reply from {0}: bytes={1} time={2}ms TTL={3}", _
            reply.Address, _
            reply.Buffer.Length, _
            reply.RoundtripTime, _
            reply.Options.Ttl) ' Time to live
        Else
          Console.WriteLine(reply.Status)
        End If

        ' ping送信の間隔を少し空ける
        If i < 3 Then
          Thread.Sleep(1000)
        End If
      Next

      Console.WriteLine(vbLf & "Ping.Send Completed.")

    Catch ex As SocketException
      Dim errorMessage As String = String.Format( _
        "ホスト {0} が見つかりませんでした。" & vbLf & _
        " → 理由:{1}", _
        address, ex.Message)
      Console.WriteLine(errorMessage)
    Catch ex As PingException
      Dim errorMessage As String = String.Format( _
        "{0} へのpingパケット送信に失敗しました。" & vbLf & _
        " → 理由:{1}", _
        address, ex.InnerException.Message)
      Console.WriteLine(errorMessage)
    End Try

  End Sub

End Module
同期通信でpingパケットを送信するサンプル・プログラム(上:C#、下:VB)

 このサンプル・プログラムでは、実際にpingパケットを送信する前に、送信先のホスト名とIPアドレスをDnsクラスのGetHostEntryメソッドを使って取得している。これについては、「TIPS:IPアドレス←→ホスト名を変換するには?」が参考になる。

 上記のコードを見ると分かるように、Ping.Sendメソッドの戻り値は、PingReplyクラス(System.Net.NetworkInformation名前空間)のオブジェクトである。このPingReplyオブジェクトが持つプロパティから、以下のようなping応答の情報を取得することができる(以下の表は、ping送信情報ではなく、ping応答情報であることに注意すること)。

プロパティ 説明
Status IPStatus列挙体(System.Net.NetworkInformation名前空間)の値により送信結果を表す。送信成功の場合は、「IPStatus.Success」という値になる。それ以外の結果情報については、MSDNのページを参照してほしい
Address ping応答パケットの送信元IPアドレス
Buffer.Length 受信したデータのバッファ・サイズ(ちなみにpingパケット送信時において、Ping.Sendメソッドにより送信されるデータのデフォルトのバッファ・サイズは32bytesだが、バッファ・サイズをパラメータに取るバージョンのSendメソッドを使えば、任意のバッファ・サイズを指定して送信することもできる)
RoundtripTime pingパケットを送信してから返答が戻ってくるまで(=ラウンドトリップ)の時間。OSの最小計測単位時間(=1ms)よりも速く戻ってきた場合は、0となることがある
Options.Ttl IPパケットを転送(IPフォワード)できる有効回数(TTL:Time to Live)。ルータやゲートウェイを通過するたびにこのTTL値はデクリメントされ、値が0になると、そのパケットは配信不能と判断され破棄される。パケットが到達可能なネットワーク的な距離(通過可能なルータ数)を制限するために利用される(値はping応答パケット送信側のOSによって異なる。ちなみに、Windows OSのTTLのデフォルト値は128である)。
このオプションはpingパケット送信時に指定することもできる。これにはPingOptionsオブジェクトをパラメータに取るバージョンのSendメソッドを使えばよい(なお、PingOptionクラスのインスタンスを生成した際のTtlプロパティの初期値は128となる)
Options.DontFragment 送信パケットのフラグメンテーション(=IPパケットを複数のパケットに分割すること)を許可するかどうかを表すBoolean値。大きなサイズのIPパケットの送信時には自動的にフラグメンテーションが行われるが、これを明示的に禁止することにより、ネットワークのMTUサイズ(Maximum Transmission Unit:一度に送信可能なパケット・サイズ)を調査するのに役立つ。送信時にこのフラグをTrueにしてpingを送信すると、応答でもこのフラグがTrueになってパケットが戻ってくる。
実際にはこのオプションは、受信結果で得るデータではなく、送信時に指定するものである。これにはPingOptionsオブジェクトをパラメータに取るバージョンのSendメソッドを使えばよい(なお、PingOptionクラスのインスタンスを生成した際のDontFragmentプロパティの初期値はFalseとなる)
PingReplyオブジェクトから利用可能なping応答情報に関するプロパティ

 ちなみにこのサンプル・プログラムの実行結果は次のようになる。

Pinging dapc89.d-advantage.com [192.168.0.102] with 32 bytes of data:

Reply from 192.168.0.102: bytes=32 time=0ms TTL=128
Reply from 192.168.0.102: bytes=32 time=0ms TTL=128
Reply from 192.168.0.102: bytes=32 time=0ms TTL=128
Reply from 192.168.0.102: bytes=32 time=0ms TTL=128

Ping.Send Completed.
同期通信でpingパケットを送信するサンプル・プログラムの実行結果
ラウンドトリップ時間(time)が0ミリ秒(0ms)になっているのは、OS内蔵のタイマーの最小単位が1msしかないため、1ms未満で戻ってくると0msとしか表現できないからだ。

 なおVisual Basic 2005のMy機能を利用する場合は、次のメソッドを呼び出すことでもpingパケットを送信できる。

My.Computer.Network.Ping("dapc89")
My機能を使って同期通信のpingパケットを送信するコード(VB)

 ただしこのメソッドでping送信を行った場合、その戻り値は送信成功(True)か、失敗(False)かを示すBoolean型のデータとなる。このため、Ping.Sendメソッドを呼び出してPingReplyオブジェクトを取得したときのような、詳細なping送信結果の情報は得られないことに注意してほしい。End of Article

カテゴリ:クラス・ライブラリ 処理対象:ネットワーク
使用ライブラリ:Pingクラス(System.Net.NetworkInformation名前空間)
使用ライブラリ:PingReplyクラス(System.Net.NetworkInformation名前空間)
使用ライブラリ:IPStatus列挙体(System.Net.NetworkInformation名前空間)
使用ライブラリ:PingOptionsクラス(System.Net.NetworkInformation名前空間)
関連TIPS:IPアドレス←→ホスト名を変換するには?

この記事と関連性の高い別の.NET TIPS
IPアドレス←→ホスト名を変換するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間