C#でPingを実行する方法|Pingクラスの使い方から疎通確認・タイムアウト対策まで解説
はじめに
C#でネットワークの疎通確認を行いたい場合、代表的な方法がPingの実行です。Pingを使うと、指定したIPアドレスやホスト名に対してICMP Echo要求を送り、相手先から応答が返ってくるかどうかを確認できます。
C#では、System.Net.NetworkInformation.Pingクラスを使うことで、コマンドプロンプトのpingコマンドを呼び出さなくても、プログラム内からPingを実行できます。
この記事では、C#でPingを実行する基本的な方法から、PingReply.Statusによる結果判定、タイムアウト設定、非同期処理、複数ホストの疎通確認、実務で使う際の注意点まで解説します。
1. C#でPingを実行する基本
1-1. Pingとは何か|疎通確認で確認できること
Pingとは、ネットワーク上の相手先にICMP Echo要求を送り、応答が返ってくるかを確認するための仕組みです。
たとえば、次のような確認に使われます。
サーバーが起動しているか
ネットワーク経路が到達可能か
IPアドレスやホスト名に応答があるか
応答までにどれくらい時間がかかるか
C#でPingを実行すると、対象ホストへの疎通可否や応答時間をプログラム上で取得できます。
ただし、PingはあくまでICMPによる確認です。Pingが成功しても、Webサイトやデータベース、APIなどのサービスが正常に動作しているとは限りません。
1-2. C#でPingを実行する主な方法
C#でPingを実行する方法には、主に次の2つがあります。
1つ目は、System.Net.NetworkInformation.Pingクラスを使う方法です。C#でPingを実行する場合は、この方法が基本になります。
2つ目は、Processクラスを使ってOSのpingコマンドを実行する方法です。ただし、コマンドの実行結果を文字列として解析する必要があるため、通常はPingクラスを使う方が扱いやすいです。
C#で疎通確認を実装するなら、まずはPingクラスを使う方法を覚えるのがおすすめです。
1-3. System.Net.NetworkInformation.Pingクラスの概要
Pingクラスは、C#からICMP Echo要求を送信するためのクラスです。
Pingクラスを使うと、指定したIPアドレスやホスト名に対してPingを送信し、その結果をPingReplyオブジェクトとして取得できます。
基本的な流れは次のとおりです。
C#using System;
using System.Net.NetworkInformation;
class Program
{
static void Main()
{
using var ping = new Ping();
PingReply reply = ping.Send("8.8.8.8");
Console.WriteLine(reply.Status);
}
}
reply.StatusがIPStatus.Successであれば、Pingに成功したと判断できます。
1-4. PingコマンドではなくC#コードで実行するメリット
C#コードでPingを実行するメリットは、結果をプログラム内で扱いやすいことです。
コマンドプロンプトのpingコマンドを実行する場合、標準出力の文字列を解析する必要があります。一方、Pingクラスを使えば、成功・失敗、応答時間、送信元・送信先情報などをオブジェクトとして取得できます。
また、次のような処理も実装しやすくなります。
Ping結果によって処理を分岐する
複数サーバーを順番に監視する
応答時間をログに出力する
タイムアウト時にリトライする
非同期で複数ホストにPingを送る
そのため、C#アプリケーション内で疎通確認を行う場合は、Pingクラスを使うのが基本です。
2. Pingクラスを使うための準備
2-1. 必要な名前空間
C#でPingクラスを使うには、次の名前空間を読み込みます。
C#using System.Net.NetworkInformation;
コンソールに結果を表示する場合は、通常どおりSystemも使用します。
C#using System;
using System.Net.NetworkInformation;
.NET 6以降のプロジェクトでは暗黙的なusingが有効になっている場合もありますが、Pingクラスを使う場合はSystem.Net.NetworkInformationを明示しておくと分かりやすいです。
2-2. Pingクラスで利用する主なメソッド
Pingクラスでよく使うメソッドは次のとおりです。
C#PingReply reply = ping.Send("8.8.8.8");
これは同期的にPingを送信する基本的なメソッドです。Pingの応答が返るまで、現在の処理は待機します。
タイムアウトを指定する場合は、次のように書きます。
C#PingReply reply = ping.Send("8.8.8.8", 3000);
第2引数の3000は、タイムアウト時間をミリ秒で指定しています。この例では3秒です。
非同期でPingを実行する場合は、SendPingAsyncメソッドを使います。
C#PingReply reply = await ping.SendPingAsync("8.8.8.8");
UIアプリや複数ホストへの並列Pingでは、非同期メソッドを使うと便利です。
2-3. PingReplyで取得できる結果
Pingの結果は、PingReplyオブジェクトとして返されます。
PingReplyでは、主に次の情報を取得できます。
C#Console.WriteLine(reply.Status);
Console.WriteLine(reply.RoundtripTime);
Console.WriteLine(reply.Address);
StatusはPingの結果を表します。成功した場合はIPStatus.Successになります。
RoundtripTimeは、応答が返るまでにかかった時間をミリ秒で表します。
Addressは、応答したIPアドレスを表します。
成功時だけでなく、タイムアウトや到達不能などの結果もStatusで判定できます。
2-4. .NET Framework・.NET Core・.NET 6以降での利用可否
Pingクラスは、.NET Framework、.NET Core、.NET 5、.NET 6以降でも利用できます。
そのため、古いWindowsアプリケーションから、現在の.NETコンソールアプリ、ASP.NET Coreアプリ、Windows Forms、WPFなどでも利用できます。
ただし、実行環境によってはICMPが制限されていたり、コンテナ環境やクラウド環境でPingが期待どおり動作しなかったりする場合があります。
C#のコード自体は正しくても、ネットワークやOS、ファイアウォールの設定によって結果が変わる点に注意が必要です。
3. C#でPingを実行する基本サンプル
3-1. 指定したIPアドレスにPingを送信するコード
まずは、IPアドレスに対してPingを送信する基本コードです。
C#using System;
using System.Net.NetworkInformation;
class Program
{
static void Main()
{
string ipAddress = "8.8.8.8";
using var ping = new Ping();
PingReply reply = ping.Send(ipAddress);
Console.WriteLine($"Status: {reply.Status}");
}
}
このコードでは、Google Public DNSのIPアドレスである8.8.8.8にPingを送信しています。
reply.StatusがSuccessであれば、Pingが成功したことを意味します。
3-2. ホスト名・ドメイン名にPingを送信するコード
IPアドレスだけでなく、ホスト名やドメイン名にもPingを送信できます。
C#using System;
using System.Net.NetworkInformation;
class Program
{
static void Main()
{
string hostName = "example.com";
using var ping = new Ping();
PingReply reply = ping.Send(hostName);
Console.WriteLine($"Status: {reply.Status}");
Console.WriteLine($"Address: {reply.Address}");
}
}
ホスト名を指定した場合、内部的に名前解決が行われます。
名前解決に成功し、対象がPingに応答すれば、StatusはSuccessになります。
3-3. Pingの成功・失敗を判定する方法
Pingの成功・失敗は、PingReply.Statusを使って判定します。
C#using System;
using System.Net.NetworkInformation;
class Program
{
static void Main()
{
string host = "8.8.8.8";
using var ping = new Ping();
PingReply reply = ping.Send(host, 3000);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine("Pingに成功しました。");
}
else
{
Console.WriteLine($"Pingに失敗しました。Status: {reply.Status}");
}
}
}
IPStatus.Successの場合のみ、相手先から応答が返ってきたと判断します。
それ以外の場合は、タイムアウト、到達不能、ネットワークエラーなどの可能性があります。
3-4. 応答時間を取得して表示する方法
応答時間はRoundtripTimeプロパティで取得できます。
C#using System;
using System.Net.NetworkInformation;
class Program
{
static void Main()
{
string host = "8.8.8.8";
using var ping = new Ping();
PingReply reply = ping.Send(host, 3000);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine($"Ping成功");
Console.WriteLine($"応答時間: {reply.RoundtripTime} ms");
Console.WriteLine($"応答元IP: {reply.Address}");
}
else
{
Console.WriteLine($"Ping失敗: {reply.Status}");
}
}
}
RoundtripTimeはミリ秒単位です。
たとえば20であれば、応答までに約20ミリ秒かかったことを意味します。
3-5. 実行結果の見方
実行結果の例は次のようになります。
Ping成功
応答時間: 12 ms
応答元IP: 8.8.8.8
この場合、Pingは成功しており、応答時間は12ミリ秒です。
一方、失敗した場合は次のように表示されることがあります。
Ping失敗: TimedOut
TimedOutは、指定した時間内に応答が返ってこなかったことを意味します。
Pingの結果を見るときは、単に成功・失敗だけでなく、Statusの内容と応答時間を確認することが重要です。
4. PingReply.Statusで疎通結果を判定する
4-1. IPStatus.Successの場合
IPStatus.Successは、Pingが成功したことを表します。
C#if (reply.Status == IPStatus.Success)
{
Console.WriteLine("疎通確認OK");
}
この状態では、対象ホストからICMP Echo応答が返ってきています。
ただし、Pingが成功したからといって、HTTP、HTTPS、SSH、RDP、SQL Serverなどのサービスに接続できるとは限りません。PingはあくまでICMPレベルの疎通確認です。
4-2. タイムアウトした場合
タイムアウトした場合、Statusは多くの場合IPStatus.TimedOutになります。
C#if (reply.Status == IPStatus.TimedOut)
{
Console.WriteLine("Pingがタイムアウトしました。");
}
タイムアウトの原因には、次のようなものがあります。
対象ホストが停止している
ネットワーク経路に問題がある
ICMPがファイアウォールでブロックされている
タイムアウト時間が短すぎる
対象サーバーの応答が遅い
タイムアウトが発生した場合は、すぐに障害と判断せず、リトライや別の接続確認方法も検討しましょう。
4-3. 到達不能・名前解決失敗の場合
対象に到達できない場合は、DestinationHostUnreachableやDestinationNetworkUnreachableなどのステータスになることがあります。
また、ホスト名の名前解決に失敗した場合は、PingExceptionなどの例外が発生することがあります。
そのため、C#でPingを実行する場合は、Statusの確認だけでなく、例外処理も必ず実装することが大切です。
C#try
{
using var ping = new Ping();
PingReply reply = ping.Send("unknown-host-name", 3000);
Console.WriteLine(reply.Status);
}
catch (PingException ex)
{
Console.WriteLine($"Pingの実行に失敗しました: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"予期しないエラー: {ex.Message}");
}
名前解決失敗、ネットワークエラー、実行環境の制限などは、戻り値ではなく例外として扱われる場合があります。
4-4. よく使うIPStatusの種類
IPStatusには多くの値がありますが、実務でよく見るものは次のとおりです。
Success
TimedOut
DestinationHostUnreachable
DestinationNetworkUnreachable
DestinationPortUnreachable
TtlExpired
PacketTooBig
Unknown
特によく使うのは、SuccessとTimedOutです。
監視や疎通確認の処理では、まずSuccessかどうかを判定し、それ以外は失敗としてログに残す実装が一般的です。
4-5. Statusごとの分岐処理サンプル
Statusごとに処理を分ける場合は、switch文を使うと分かりやすくなります。
C#using System;
using System.Net.NetworkInformation;
class Program
{
static void Main()
{
string host = "8.8.8.8";
using var ping = new Ping();
PingReply reply = ping.Send(host, 3000);
switch (reply.Status)
{
case IPStatus.Success:
Console.WriteLine($"成功: {reply.RoundtripTime} ms");
break;
case IPStatus.TimedOut:
Console.WriteLine("タイムアウトしました。");
break;
case IPStatus.DestinationHostUnreachable:
Console.WriteLine("宛先ホストに到達できません。");
break;
case IPStatus.DestinationNetworkUnreachable:
Console.WriteLine("宛先ネットワークに到達できません。");
break;
default:
Console.WriteLine($"その他のエラー: {reply.Status}");
break;
}
}
}
実務では、Success以外をすべて失敗として扱い、詳細なStatusをログに出力しておくと調査しやすくなります。
5. タイムアウトを指定してPingを実行する方法
5-1. Sendメソッドでタイムアウトを設定する
C#のPing.Sendメソッドでは、タイムアウト時間をミリ秒で指定できます。
C#using System;
using System.Net.NetworkInformation;
class Program
{
static void Main()
{
string host = "8.8.8.8";
int timeout = 3000;
using var ping = new Ping();
PingReply reply = ping.Send(host, timeout);
Console.WriteLine($"Status: {reply.Status}");
}
}
この例では、3秒以内に応答が返らなければタイムアウトとして扱われます。
タイムアウトを指定しないと、環境によって待ち時間が長くなることがあります。実務で使う疎通確認では、明示的にタイムアウトを設定するのがおすすめです。
5-2. タイムアウト時間の適切な目安
タイムアウト時間は、用途やネットワーク環境によって変える必要があります。
社内LANなど応答が速い環境では、1000ミリ秒から3000ミリ秒程度でも十分な場合があります。
インターネット越しのサーバーやVPN経由の環境では、3000ミリ秒から5000ミリ秒程度に設定することが多いです。
ただし、タイムアウトを長くしすぎると、複数ホストを監視する際に処理全体が遅くなります。逆に短すぎると、一時的な遅延で失敗扱いになる可能性があります。
5-3. タイムアウト時の戻り値と例外の違い
Pingのタイムアウトは、通常PingReply.StatusがIPStatus.TimedOutになります。
C#PingReply reply = ping.Send("8.8.8.8", 1000);
if (reply.Status == IPStatus.TimedOut)
{
Console.WriteLine("タイムアウトしました。");
}
一方で、ホスト名の名前解決に失敗した場合や、Pingの送信自体に問題がある場合は、PingExceptionなどの例外が発生することがあります。
つまり、C#でPingを安全に実行するには、次の両方を考慮する必要があります。
PingReply.Statusによる結果判定try-catchによる例外処理
タイムアウトは戻り値で返ることが多いですが、すべての失敗が戻り値で返るわけではありません。
5-4. タイムアウト時にリトライする実装例
一時的なネットワーク遅延を考慮する場合は、タイムアウト時にリトライする実装が有効です。
C#using System;
using System.Net.NetworkInformation;
using System.Threading;
class Program
{
static void Main()
{
string host = "8.8.8.8";
int timeout = 2000;
int retryCount = 3;
bool success = PingWithRetry(host, timeout, retryCount);
Console.WriteLine(success ? "疎通確認OK" : "疎通確認NG");
}
static bool PingWithRetry(string host, int timeout, int retryCount)
{
using var ping = new Ping();
for (int i = 1; i <= retryCount; i++)
{
try
{
PingReply reply = ping.Send(host, timeout);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine($"成功: {reply.RoundtripTime} ms");
return true;
}
Console.WriteLine($"失敗 {i}回目: {reply.Status}");
}
catch (PingException ex)
{
Console.WriteLine($"PingException {i}回目: {ex.Message}");
}
Thread.Sleep(1000);
}
return false;
}
}
このサンプルでは、最大3回までPingを実行します。
一時的なパケットロスや遅延がある環境では、1回の失敗だけで障害と判断せず、数回リトライする方が安定します。
5-5. 応答が遅い環境で注意すべきポイント
VPN、無線LAN、遠隔拠点、クラウド環境などでは、Pingの応答が遅くなることがあります。
そのような環境では、タイムアウトを短く設定しすぎると、実際には到達可能なのに失敗と判定されることがあります。
また、ネットワークの混雑や一時的な遅延によって、応答時間が大きく変動することもあります。
実務では、次のような設計にすると安定します。
タイムアウトを環境に合わせて調整する
1回ではなく複数回リトライする
応答時間もログに残す
連続失敗した場合のみアラートを出す
Ping以外の確認方法も組み合わせる
Pingの結果はネットワーク状態に左右されるため、短絡的に成功・失敗だけで判断しないことが大切です。
6. 非同期でPingを実行する方法
6-1. SendPingAsyncメソッドの使い方
C#で非同期にPingを実行する場合は、SendPingAsyncメソッドを使います。
C#PingReply reply = await ping.SendPingAsync("8.8.8.8");
同期メソッドのSendは、応答が返るまで処理を待機します。
一方、SendPingAsyncを使うと、Pingの完了を待っている間も他の処理を進められます。
特に、次のようなケースでは非同期処理が有効です。
複数ホストへ同時にPingを送る
Windows FormsやWPFなどのUIアプリで使う
ASP.NET Coreなどで待機時間を効率化する
定期監視処理でレスポンスを改善する
6-2. async/awaitを使ったPing実行サンプル
async/awaitを使った基本的なPing実行例です。
C#using System;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
string host = "8.8.8.8";
using var ping = new Ping();
PingReply reply = await ping.SendPingAsync(host, 3000);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine($"Ping成功: {reply.RoundtripTime} ms");
}
else
{
Console.WriteLine($"Ping失敗: {reply.Status}");
}
}
}
awaitを使うことで、非同期処理でも同期処理に近い形で読みやすく書けます。
.NET Coreや.NET 6以降では、static async Task Main()を使ってコンソールアプリのエントリポイントを非同期にできます。
6-3. 複数ホストへ並列にPingを実行する方法
複数ホストにPingを送る場合、1件ずつ順番に実行すると時間がかかります。
Task.WhenAllを使うと、複数のPingを並列に実行できます。
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var hosts = new[]
{
"8.8.8.8",
"1.1.1.1",
"example.com"
};
var tasks = hosts.Select(host => PingHostAsync(host));
var results = await Task.WhenAll(tasks);
foreach (var result in results)
{
Console.WriteLine(result);
}
}
static async Task<string> PingHostAsync(string host)
{
try
{
using var ping = new Ping();
PingReply reply = await ping.SendPingAsync(host, 3000);
if (reply.Status == IPStatus.Success)
{
return $"{host}: OK {reply.RoundtripTime} ms";
}
return $"{host}: NG {reply.Status}";
}
catch (PingException ex)
{
return $"{host}: Error {ex.Message}";
}
}
}
複数サーバーの監視や一括疎通確認では、このような非同期並列処理が便利です。
ただし、大量のホストに一度にPingを送るとネットワーク負荷が高くなるため、対象数が多い場合は同時実行数を制限しましょう。
6-4. 非同期処理でタイムアウトを扱う方法
SendPingAsyncにもタイムアウトを指定できます。
C#PingReply reply = await ping.SendPingAsync("8.8.8.8", 3000);
この例では、3秒以内に応答が返らなければタイムアウトになります。
また、アプリケーション全体のキャンセル制御を行いたい場合は、TaskやCancellationTokenと組み合わせる設計も検討できます。
ただし、基本的なPingのタイムアウトであれば、まずはSendPingAsyncのタイムアウト引数を使うのが分かりやすいです。
6-5. UIアプリで画面が固まらないようにするポイント
Windows FormsやWPFなどのUIアプリで同期版のSendメソッドを使うと、Pingの応答待ち中に画面が固まることがあります。
UIアプリでは、次のようにasync/awaitを使って非同期に実行するのがおすすめです。
C#private async void buttonPing_Click(object sender, EventArgs e)
{
using var ping = new Ping();
try
{
PingReply reply = await ping.SendPingAsync("8.8.8.8", 3000);
labelResult.Text = reply.Status == IPStatus.Success
? $"成功: {reply.RoundtripTime} ms"
: $"失敗: {reply.Status}";
}
catch (PingException ex)
{
labelResult.Text = $"エラー: {ex.Message}";
}
}
非同期処理にすることで、Pingの応答待ち中でも画面操作が止まりにくくなります。
UIアプリでは、時間のかかる処理をUIスレッドで直接実行しないことが重要です。
7. Ping実行時によくあるエラーと対策
7-1. PingExceptionが発生する原因
PingExceptionは、Pingの送信処理中に問題が発生した場合に発生します。
主な原因は次のとおりです。
ホスト名を名前解決できない
ネットワークに接続されていない
ICMPの送信が制限されている
実行環境でPingが許可されていない
不正なホスト名やアドレスを指定している
PingExceptionが発生した場合は、InnerExceptionに詳細な原因が含まれていることがあります。
C#catch (PingException ex)
{
Console.WriteLine(ex.Message);
if (ex.InnerException != null)
{
Console.WriteLine(ex.InnerException.Message);
}
}
例外メッセージだけでなく、対象ホスト名、タイムアウト時間、実行環境もあわせて確認しましょう。
7-2. ホスト名が解決できない場合の対処
ホスト名が解決できない場合、Pingは実行前の名前解決で失敗します。
対処方法としては、次の点を確認します。
ホスト名に誤字がないか
DNSサーバーが利用できるか
社内DNSが必要な環境ではないか
VPN接続が必要ではないか
IPアドレスを直接指定すると成功するか
ホスト名で失敗し、IPアドレスで成功する場合は、ネットワーク疎通ではなく名前解決に問題がある可能性が高いです。
C#側では、例外処理で名前解決失敗を検知し、ログに残すようにします。
C#try
{
using var ping = new Ping();
PingReply reply = ping.Send("server01.local", 3000);
Console.WriteLine(reply.Status);
}
catch (PingException ex)
{
Console.WriteLine($"ホスト名の解決またはPing送信に失敗しました: {ex.Message}");
}
7-3. ファイアウォールでICMPがブロックされる場合
PingはICMPを使います。
そのため、対象サーバーやネットワーク機器、クラウド環境のファイアウォールでICMPがブロックされていると、サーバー自体は動作していてもPingは失敗します。
たとえば、次のような環境ではICMPが無効になっていることがあります。
Windows FirewallでICMP Echo応答が無効
クラウドのセキュリティグループでICMPを許可していない
ルーターやVPN機器でICMPを遮断している
セキュリティポリシーでPing応答を禁止している
この場合、C#のPingコードを修正しても解決しません。
Pingが失敗する場合は、対象サーバーのICMP応答設定やネットワーク機器の設定も確認しましょう。
7-4. 管理者権限や実行環境による制限
環境によっては、Pingの実行に制限がある場合があります。
特に、Linux、macOS、コンテナ、クラウド実行環境などでは、ICMPの送信に権限や設定が関係することがあります。
また、サーバーレス環境や制限されたコンテナ環境では、Pingそのものが利用できない場合もあります。
C#のコードが正しくても、実行環境側の制限で失敗することがあるため、次の点を確認しましょう。
ローカルPCでは成功するか
サーバー上で同じ宛先にPingできるか
コンテナ内からPingできるか
クラウド側でICMPが許可されているか
実行ユーザーに必要な権限があるか
実務では、Pingに依存しすぎず、TCP接続やHTTPリクエストによる確認も併用するのが安全です。
7-5. 例外処理を含めた安全な実装例
Pingを安全に実行するには、try-catchで例外を捕捉し、Statusも確認します。
C#using System;
using System.Net.NetworkInformation;
class Program
{
static void Main()
{
string host = "example.com";
int timeout = 3000;
bool result = IsPingSuccess(host, timeout);
Console.WriteLine(result ? "疎通OK" : "疎通NG");
}
static bool IsPingSuccess(string host, int timeout)
{
try
{
using var ping = new Ping();
PingReply reply = ping.Send(host, timeout);
return reply.Status == IPStatus.Success;
}
catch (PingException ex)
{
Console.WriteLine($"Pingエラー: {ex.Message}");
return false;
}
catch (Exception ex)
{
Console.WriteLine($"予期しないエラー: {ex.Message}");
return false;
}
}
}
このようにメソッド化しておくと、アプリケーション内の複数箇所で再利用できます。
実務では、falseを返すだけでなく、エラー内容をログファイルや監視システムに記録すると原因調査がしやすくなります。
8. PingOptionsを使った詳細設定
8-1. PingOptionsでTTLを指定する
PingOptionsを使うと、Ping送信時の詳細設定を指定できます。
代表的な設定がTTLです。
TTLは、パケットが通過できるルーターの最大数を表します。TTLが0になると、パケットは破棄されます。
C#では、次のようにPingOptionsを作成します。
C#PingOptions options = new PingOptions
{
Ttl = 64
};
TTLを指定することで、ネットワーク経路の調査や制限付きの疎通確認に利用できます。
8-2. DontFragmentを設定する
PingOptionsでは、DontFragmentも指定できます。
C#PingOptions options = new PingOptions
{
DontFragment = true
};
DontFragmentをtrueにすると、送信するパケットを分割しないように指定します。
パケットサイズと組み合わせることで、経路上のMTU問題を調査する際に使われることがあります。
ただし、通常の疎通確認ではDontFragmentを意識する必要はあまりありません。
8-3. バッファサイズを指定してPingを送る
Pingでは、送信するデータのバッファを指定できます。
C#byte[] buffer = new byte[32];
この例では、32バイトのデータを送信します。
バッファサイズを大きくすると、より大きなパケットで疎通確認できます。
ただし、大きすぎるバッファを指定すると、環境によっては失敗することがあります。通常の疎通確認では、32バイト程度で十分です。
8-4. ネットワーク調査でPingOptionsを使う場面
PingOptionsは、単純な生存確認よりも、ネットワーク調査で使われることが多いです。
たとえば、次のような場面です。
TTLを変えて経路上の挙動を調べる
パケット分割を禁止してMTU問題を確認する
バッファサイズを変えて通信経路の状態を確認する
特定環境でパケットが破棄される条件を調べる
通常のアプリケーションでは、タイムアウトとStatus判定だけで十分なことが多いです。
一方、ネットワーク診断ツールのような用途では、PingOptionsを使うことでより細かい制御ができます。
8-5. PingOptionsを使ったコード例
PingOptionsを使ってPingを実行するサンプルです。
C#using System;
using System.Net.NetworkInformation;
using System.Text;
class Program
{
static void Main()
{
string host = "8.8.8.8";
int timeout = 3000;
using var ping = new Ping();
byte[] buffer = Encoding.ASCII.GetBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
PingOptions options = new PingOptions
{
Ttl = 64,
DontFragment = true
};
PingReply reply = ping.Send(host, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine($"Ping成功: {reply.RoundtripTime} ms");
Console.WriteLine($"TTL: {options.Ttl}");
}
else
{
Console.WriteLine($"Ping失敗: {reply.Status}");
}
}
}
このコードでは、TTLを64、DontFragmentをtrueに設定しています。
バッファには32バイトの文字列を指定しています。
詳細なネットワーク調査を行う場合は、TTLやバッファサイズを変えながら結果を比較するとよいでしょう。
9. 実務で使える疎通確認プログラムの作り方
9-1. 複数サーバーの生存確認を行う
実務では、1台だけでなく複数サーバーに対して疎通確認を行うことがよくあります。
たとえば、次のような対象です。
Webサーバー
DBサーバー
ファイルサーバー
ルーター
社内システムのサーバー
外部APIの接続先
複数サーバーを確認する場合は、ホスト一覧を配列や設定ファイルで管理し、順番にPingを実行します。
C#string[] hosts =
{
"8.8.8.8",
"1.1.1.1",
"example.com"
};
ホスト数が少ない場合は同期処理でも問題ありませんが、数十件以上になる場合は非同期処理や同時実行数の制限を検討しましょう。
9-2. Ping結果を一覧表示する
複数ホストのPing結果を一覧表示するサンプルです。
C#using System;
using System.Net.NetworkInformation;
class Program
{
static void Main()
{
string[] hosts =
{
"8.8.8.8",
"1.1.1.1",
"example.com"
};
foreach (string host in hosts)
{
PingResult result = CheckPing(host);
Console.WriteLine($"{result.Host} | {result.IsSuccess} | {result.Status} | {result.RoundtripTime} ms");
}
}
static PingResult CheckPing(string host)
{
try
{
using var ping = new Ping();
PingReply reply = ping.Send(host, 3000);
return new PingResult
{
Host = host,
IsSuccess = reply.Status == IPStatus.Success,
Status = reply.Status.ToString(),
RoundtripTime = reply.Status == IPStatus.Success ? reply.RoundtripTime : -1
};
}
catch (Exception ex)
{
return new PingResult
{
Host = host,
IsSuccess = false,
Status = ex.GetType().Name,
RoundtripTime = -1
};
}
}
}
class PingResult
{
public string Host { get; set; } = "";
public bool IsSuccess { get; set; }
public string Status { get; set; } = "";
public long RoundtripTime { get; set; }
}
実行結果の例です。
8.8.8.8 | True | Success | 10 ms
1.1.1.1 | True | Success | 8 ms
example.com | True | Success | 25 ms
結果をオブジェクトとして持つことで、画面表示、ログ出力、CSV出力などに展開しやすくなります。
9-3. 成功・失敗をログに出力する
実務の監視用途では、Ping結果をコンソールに表示するだけでなく、ログに出力することが重要です。
簡単な例として、テキストファイルにログを追記するコードを紹介します。
C#using System;
using System.IO;
using System.Net.NetworkInformation;
class Program
{
static void Main()
{
string host = "8.8.8.8";
string logFile = "ping.log";
using var ping = new Ping();
try
{
PingReply reply = ping.Send(host, 3000);
string message = reply.Status == IPStatus.Success
? $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {host} OK {reply.RoundtripTime}ms"
: $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {host} NG {reply.Status}";
File.AppendAllText(logFile, message + Environment.NewLine);
Console.WriteLine(message);
}
catch (Exception ex)
{
string message = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {host} ERROR {ex.Message}";
File.AppendAllText(logFile, message + Environment.NewLine);
Console.WriteLine(message);
}
}
}
ログには、日時、対象ホスト、成功・失敗、応答時間、エラー内容を含めると便利です。
障害調査では、「いつから失敗していたか」「応答時間が徐々に遅くなっていないか」を確認できることが重要です。
9-4. 定期的にPingを実行する
定期的にPingを実行する場合は、Timerやバックグラウンド処理を使います。
簡単なコンソールアプリでは、ループとTask.Delayで定期実行できます。
C#using System;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
string host = "8.8.8.8";
while (true)
{
await CheckPingAsync(host);
await Task.Delay(TimeSpan.FromSeconds(10));
}
}
static async Task CheckPingAsync(string host)
{
try
{
using var ping = new Ping();
PingReply reply = await ping.SendPingAsync(host, 3000);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss} OK {reply.RoundtripTime}ms");
}
else
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss} NG {reply.Status}");
}
}
catch (Exception ex)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss} ERROR {ex.Message}");
}
}
}
この例では、10秒ごとにPingを実行します。
本格的な監視ツールにする場合は、設定ファイル、ログローテーション、通知機能、停止処理なども考慮しましょう。
9-5. 監視ツールとして実装する際の注意点
C#でPing監視ツールを作る場合は、単にPingを送るだけでは不十分です。
実務では、次の点を考慮する必要があります。
監視対象を設定ファイルで管理する
タイムアウト時間を変更できるようにする
リトライ回数を設定できるようにする
連続失敗時のみ通知する
結果をログやデータベースに保存する
大量Pingでネットワーク負荷をかけない
ICMPが無効なサーバーへの代替確認を用意する
また、Ping成功は「サーバーがICMPに応答した」ことを意味するだけです。
アプリケーションの稼働状況まで監視したい場合は、HTTPヘルスチェックやTCP接続確認、ログ監視なども組み合わせる必要があります。
10. C#のPingで確認できないこと
10-1. Ping成功でもWebサイトに接続できるとは限らない理由
Pingが成功しても、Webサイトにアクセスできるとは限りません。
なぜなら、PingはICMPであり、WebサイトはHTTPまたはHTTPSで通信するためです。
たとえば、次のようなケースではPingが成功してもWebサイトは利用できません。
Webサーバーのサービスが停止している
80番や443番ポートが閉じている
アプリケーションがエラーを返している
SSL証明書に問題がある
ロードバランサーやプロキシに問題がある
Pingはネットワーク到達性の確認には便利ですが、Webサービスの正常性確認には不十分です。
Webサイトの状態を確認したい場合は、HttpClientを使ってHTTPレスポンスを確認しましょう。
10-2. ポート開放確認にはPingではなくTCP接続を使う
特定のポートが開いているか確認したい場合、Pingでは確認できません。
たとえば、次のような確認です。
Webサーバーの443番ポートが開いているか
SSHの22番ポートに接続できるか
SQL Serverの1433番ポートに接続できるか
Redisの6379番ポートに接続できるか
このような場合は、TcpClientを使ってTCP接続を試す必要があります。
C#using System;
using System.Net.Sockets;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
bool result = await CheckTcpPortAsync("example.com", 443, 3000);
Console.WriteLine(result ? "ポート接続OK" : "ポート接続NG");
}
static async Task<bool> CheckTcpPortAsync(string host, int port, int timeout)
{
try
{
using var client = new TcpClient();
Task connectTask = client.ConnectAsync(host, port);
Task timeoutTask = Task.Delay(timeout);
Task completedTask = await Task.WhenAny(connectTask, timeoutTask);
if (completedTask == timeoutTask)
{
return false;
}
await connectTask;
return true;
}
catch
{
return false;
}
}
}
ポート開放確認が目的であれば、C#のPingではなくTCP接続を使いましょう。
10-3. ICMPが無効な環境での代替手段
サーバーやネットワークによっては、ICMPが無効化されていることがあります。
その場合、Pingは失敗しますが、実際にはサービスが正常に動作していることもあります。
ICMPが使えない環境では、次のような代替手段を使います。
HttpClientでHTTP/HTTPSのヘルスチェックを行うTcpClientで指定ポートに接続するデータベース接続を試す
アプリケーションのヘルスチェックAPIを呼び出す
クラウドの監視サービスを使う
重要なのは、確認したい対象に合った方法を選ぶことです。
ネットワーク疎通を確認したいならPing、Webアプリの稼働確認ならHTTPリクエスト、ポート確認ならTCP接続を使います。
10-4. HttpClientやTcpClientとの使い分け
C#では、Ping以外にも通信確認に使えるクラスがあります。
Pingは、ICMPによる疎通確認に使います。
C#using var ping = new Ping();
PingReply reply = ping.Send("8.8.8.8");
HttpClientは、WebサイトやWeb APIの確認に使います。
C#using var client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("https://example.com");
TcpClientは、特定ポートへの接続確認に使います。
C#using var client = new TcpClient();
await client.ConnectAsync("example.com", 443);
使い分けの目安は次のとおりです。
ネットワーク到達性の確認: Ping
Webサイト・APIの確認: HttpClient
ポート開放確認: TcpClient
Pingだけで全てを確認しようとせず、目的に応じて適切な方法を選ぶことが大切です。
10-5. Pingだけに依存しない疎通確認設計
実務では、Pingだけに依存した監視設計は避けるべきです。
Pingは便利ですが、確認できる範囲は限定的です。
たとえば、サーバーがPingに応答していても、アプリケーションが停止していればユーザーにとっては障害です。
逆に、セキュリティ上の理由でPingを拒否しているサーバーでも、Webサービスは正常に動作している場合があります。
そのため、監視設計では次のように複数の観点を組み合わせます。
Pingでネットワーク到達性を確認する
TCP接続でポート開放を確認する
HTTPリクエストでWebアプリの応答を確認する
DB接続でデータベースの稼働を確認する
ログやメトリクスでアプリケーション状態を確認する
Pingは疎通確認の入り口として有効ですが、サービス監視では他の確認方法と組み合わせることが重要です。
11. C#でPingを使うときのベストプラクティス
11-1. usingでPingオブジェクトを破棄する
PingクラスはIDisposableを実装しているため、使用後は破棄します。
C#では、usingを使うのが基本です。
C#using var ping = new Ping();
PingReply reply = ping.Send("8.8.8.8", 3000);
または、従来のusing文でも問題ありません。
C#using (var ping = new Ping())
{
PingReply reply = ping.Send("8.8.8.8", 3000);
}
リソースを適切に解放するためにも、Pingオブジェクトは使い終わったら破棄しましょう。
11-2. タイムアウトとリトライ回数を適切に設定する
Pingを実務で使う場合は、タイムアウトとリトライ回数を適切に設定することが重要です。
タイムアウトが短すぎると、一時的な遅延で失敗扱いになります。
逆に長すぎると、障害検知が遅くなったり、複数ホストの確認に時間がかかったりします。
一般的には、次のような設定から始めるとよいでしょう。
タイムアウト: 1000〜5000ミリ秒
リトライ回数: 2〜3回
リトライ間隔: 1〜5秒
ただし、最適な値はネットワーク環境によって異なります。
運用しながら、誤検知が多い場合はタイムアウトやリトライ回数を調整しましょう。
11-3. 例外処理を必ず実装する
Pingでは、Statusが失敗を表す場合だけでなく、例外が発生する場合もあります。
そのため、必ずtry-catchを実装しましょう。
C#try
{
using var ping = new Ping();
PingReply reply = ping.Send("example.com", 3000);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine("成功");
}
else
{
Console.WriteLine($"失敗: {reply.Status}");
}
}
catch (PingException ex)
{
Console.WriteLine($"Pingエラー: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"予期しないエラー: {ex.Message}");
}
例外処理を入れておかないと、名前解決失敗やネットワークエラーでアプリケーションが停止する可能性があります。
疎通確認処理は失敗することを前提に、安全に実装することが大切です。
11-4. 大量Pingによる負荷に注意する
多数のホストに対して短い間隔でPingを送り続けると、ネットワークや対象サーバーに負荷をかける可能性があります。
特に、次のような実装には注意が必要です。
数百台に同時にPingを送る
1秒未満の短い間隔で繰り返す
タイムアウトが長いまま大量実行する
失敗時に無制限リトライする
外部サービスに対して高頻度にPingする
大量のPingを実行する場合は、同時実行数を制限し、実行間隔を適切に設定しましょう。
監視用途では、Pingの頻度を必要最低限に抑えることも大切です。
11-5. IPv4・IPv6環境を考慮する
現在のネットワークでは、IPv4だけでなくIPv6も使われることがあります。
ホスト名を指定してPingを実行した場合、環境によってIPv4アドレスまたはIPv6アドレスに解決されることがあります。
そのため、IPv4とIPv6のどちらに疎通しているのかを確認したい場合は、reply.Addressを出力すると分かりやすくなります。
C#using var ping = new Ping();
PingReply reply = ping.Send("example.com", 3000);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine($"応答元IP: {reply.Address}");
Console.WriteLine($"アドレス種別: {reply.Address.AddressFamily}");
}
IPv4のみ確認したい場合はIPv4アドレスを直接指定し、IPv6を確認したい場合はIPv6アドレスを指定します。
ホスト名を使う場合は、DNSの設定や実行環境によって結果が変わる可能性があるため注意しましょう。
まとめ
C#でPingを実行するには、System.Net.NetworkInformation.Pingクラスを使います。
基本的な流れは、Pingオブジェクトを作成し、SendまたはSendPingAsyncでPingを送信し、戻り値のPingReply.Statusで結果を判定する形です。
同期処理ではSend、非同期処理ではSendPingAsyncを使います。
C#using var ping = new Ping();
PingReply reply = ping.Send("8.8.8.8", 3000);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine($"Ping成功: {reply.RoundtripTime} ms");
}
else
{
Console.WriteLine($"Ping失敗: {reply.Status}");
}
実務でC#のPingを使う場合は、タイムアウト、リトライ、例外処理、ログ出力を必ず考慮しましょう。
また、PingはICMPによる疎通確認であり、Webサイトやポート、アプリケーションの正常性までは確認できません。
Webサイトの確認にはHttpClient、ポート確認にはTcpClientを使い、目的に応じて確認方法を使い分けることが重要です。
C#でPingを正しく使えば、サーバー監視、ネットワーク診断、疎通確認ツールなどを効率よく実装できます。

