利用 System.Diagnostics.Process 啟動 cmd.exe,重導向標準輸入/輸出/錯誤流,寫入 ping 指令並讀取輸出結果。此法不需 P/Invoke 呼叫 ICMP API,相容性佳。
using System;
using System.Diagnostics;
using System.Text;
public class PingHelper
{
///
/// 執行 ping 並回傳原始輸出文字
///
public static string Ping(string ipAddress, int count = 1, int timeoutMs = 3000)
{
var psi = new ProcessStartInfo
{
FileName = "cmd.exe",
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
StandardOutputEncoding = Encoding.GetEncoding(950), // 繁中系統預設 Big5 (CP950)
StandardErrorEncoding = Encoding.GetEncoding(950)
};
using (var proc = Process.Start(psi))
{
// 寫入 ping 指令:-n 指定次數,-w 指定超時(ms)
proc.StandardInput.WriteLine($"ping -n {count} -w {timeoutMs} {ipAddress}");
proc.StandardInput.WriteLine("exit");
proc.StandardInput.Close();
string output = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit(5000); // 保護性等待
if (!string.IsNullOrEmpty(error))
return $"ERROR: {error}";
return output;
}
}
///
/// 簡易判斷是否可達
///
public static bool IsReachable(string ipAddress)
{
string result = Ping(ipAddress);
// 簡單關鍵字判斷,實務建議用 Regex 擷取 "TTL=" 或 "Reply from"
return result.Contains("TTL=") || result.Contains("Reply from") || result.Contains("回覆");
}
}
string ip = "8.8.8.8";
string raw = PingHelper.Ping(ip, count: 3);
Console.WriteLine(raw);
if (PingHelper.IsReachable(ip))
Console.WriteLine($"{ip} 可連線");
else
Console.WriteLine($"{ip} 不可連線");
public class PingResult
{
public bool Success { get; set; }
public int Sent { get; set; }
public int Received { get; set; }
public int Lost { get; set; }
public int MinMs { get; set; }
public int MaxMs { get; set; }
public int AvgMs { get; set; }
}
public static PingResult ParsePingOutput(string output)
{
var result = new PingResult();
// 以正規表示式擷取統計行,例:
// "已傳送 = 3,已收到 = 3,失敗 = 0 (0% 遺失),"
// "最短 = 5ms,最長 = 8ms,平均 = 6ms"
var statsMatch = Regex.Match(output, @"已傳送\s*=\s*(\d+).*?已收到\s*=\s*(\d+).*?失敗\s*=\s*(\d+)");
if (statsMatch.Success)
{
result.Sent = int.Parse(statsMatch.Groups[1].Value);
result.Received = int.Parse(statsMatch.Groups[2].Value);
result.Lost = int.Parse(statsMatch.Groups[3].Value);
result.Success = result.Received > 0;
}
var timeMatch = Regex.Match(output, @"最短\s*=\s*(\d+)ms.*?最長\s*=\s*(\d+)ms.*?平均\s*=\s*(\d+)ms");
if (timeMatch.Success)
{
result.MinMs = int.Parse(timeMatch.Groups[1].Value);
result.MaxMs = int.Parse(timeMatch.Groups[2].Value);
result.AvgMs = int.Parse(timeMatch.Groups[3].Value);
}
return result;
}
| 方案 | 優點 | 缺點 |
|---|---|---|
| Process + ping.exe | 無需管理員權限、跨平台(Linux/macOS 亦有 ping)、支援主機名解析 | 啟動進程開銷大、解析輸出需處理多語系 |
System.Net.NetworkInformation.Ping | Managed API、效能佳、強型別回傳、支援非同步 | 需 .NET 2.0+、部分舊版 OS 需管理員權限 |
| ICMP DLL (IcmpSendEcho) | 底層控制最細 | P/Invoke 複雜、需管理員權限、易出錯 |
現代 .NET 專案請直接使用 System.Net.NetworkInformation.Ping,僅在舊版框架、特殊權限限制或需相容非 Windows 平台時才考慮 Process 方案。
// 現代寫法(.NET Core / .NET 5+ / .NET Framework 2.0+)
using System.Net.NetworkInformation;
var ping = new Ping();
var reply = ping.Send("8.8.8.8", 3000);
if (reply.Status == IPStatus.Success)
Console.WriteLine($"RTT: {reply.RoundtripTime} ms");