icscs著
本文主要是用于熟悉.NET 2.0中一个新的命名空间System.Net.NetworkInformation的使用,这个命名空间包括了一个Ping类...
翻译
Stefan Prodan著Ping.exe replica in C# 2.0
简介
我正在做一个应用程序,它需要连接到一个webservice并和它交换数据。因此在创建proxy对象之前,我需要检查这个客户端是否已经连接到inernet,是否能够访问到Webservice的网络地址。最容易的方法是使用Process类直接调用Ping.exe应用程序,然后获取我需要的信息。但是,为了这么小的一个功能就去调用一个外部应用程序是很不好代码,更不用说还有调用系统组件的安全性问题。在 .NET Framework 1.0 或 1.1中,微软并没有提供一个类似ping功能的类。不过,在搜索了MSDN之后,我发现在C#2.0中,有一个新的命名空间System.Net.NetworkInformation,这个命名空间包括了一个Ping类。
因此,我写了一个仅仅包含170行代码的控制台应用程序熟悉这个类的使用。

背景
MSDN 对System.Net.NetworkInformation.Ping 类的描述 http://msdn2.microsoft.com/en-us/library/system.net.networkinformation.ping.aspx
Wesley Brown在CodeProject上发表的C# 1.1 Ping Component
http://www.codeproject.com/dotnet/CSharpPing.asp
参考本站的译文C#实现ping功能(.net 1.1)
代码使用
这个应用程序的Main方法非常简单;它需要一个地址,然后调用DNS.GetHostEntry方法处理这个地址。不过在处理之前,调用了IsOffline方法,用以判断客户端是否连接到因特网。IsOffline方法使用系统链接库Winnet中的InternetGetConnectedState方法。
检查因特网连接
[Flags]
enum ConnectionState : int
{
INTERNET_CONNECTION_MODEM = 0x1,
INTERNET_CONNECTION_LAN = 0x2,
INTERNET_CONNECTION_PROXY = 0x4,
INTERNET_RAS_INSTALLED = 0x10,
INTERNET_CONNECTION_OFFLINE = 0x20,
INTERNET_CONNECTION_CONFIGURED = 0x40
}
[DllImport("wininet", CharSet = CharSet.Auto)]
static extern bool InternetGetConnectedState(ref ConnectionState lpdwFlags,
int dwReserved);
static bool IsOffline()
{
ConnectionState state = 0;
InternetGetConnectedState(ref state, 0);
if (((int)ConnectionState.INTERNET_CONNECTION_OFFLINE & (int)state) != 0)
{
return true;
}
return false;
}
在一个StartPing方法的线程中执行ping
static void StartPing(object argument)
{
IPAddress ip = (IPAddress)argument;
//set options ttl=128 and no fragmentation
PingOptions options = new PingOptions(128, true);
//创建一个Ping对象
Ping ping = new Ping();
//32个空字节的缓冲区
byte[] data = new byte[32];
int received = 0;
List<long> responseTimes = new List<long>();
//ping 4 次
for (int i = 0; i < 4; i++)
{
PingReply reply = ping.Send(ip, 1000, data, options);
if (reply != null)
{
switch (reply.Status)
{
case IPStatus.Success:
Console.WriteLine("Reply from {0}: " +
"bytes={1} time={2}ms TTL={3}",
reply.Address, reply.Buffer.Length,
reply.RoundtripTime, reply.Options.Ttl);
received++;
responseTimes.Add(reply.RoundtripTime);
break;
case IPStatus.TimedOut:
Console.WriteLine("Request timed out.");
break;
default:
Console.WriteLine("Ping failed {0}",
reply.Status.ToString());
break;
}
}
else
{
Console.WriteLine("Ping failed for an unknown reason");
}
}
//统计信息
long averageTime = -1;
long minimumTime = 0;
long maximumTime = 0;
for (int i = 0; i < responseTimes.Count; i++)
{
if (i == 0)
{
minimumTime = responseTimes[i];
maximumTime = responseTimes[i];
}
else
{
if (responseTimes[i] > maximumTime)
{
maximumTime = responseTimes[i];
}
if (responseTimes[i] < minimumTime)
{
minimumTime = responseTimes[i];
}
}
averageTime += responseTimes[i];
}
StringBuilder statistics = new StringBuilder();
statistics.AppendFormat("Ping statistics for {0}:", ip.ToString());
statistics.AppendLine();
statistics.AppendFormat(" Packets: Sent = 4, " +
"Received = {0}, Lost = {1} <{2}% loss>,",
received, 4 - received, Convert.ToInt32(((4 - received) * 100) / 4));
statistics.AppendLine();
statistics.Append("Approximate round trip times in milli-seconds:");
statistics.AppendLine();
//在loss不为100%时显示
if (averageTime != -1)
{
statistics.AppendFormat(" Minimum = {0}ms, " +
"Maximum = {1}ms, Average = {2}ms",
minimumTime, maximumTime, (long)(averageTime / received));
}
Console.WriteLine();
Console.WriteLine(statistics.ToString());
Console.WriteLine();
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
Main函数首先检查用户是否输入了一个IP,然后验证是否连接到因特网,转换到IPAddress 类型,并开始线程。
static void Main(string[] args)
{
string address = string.Empty;
if (args.Length == 0)
{
Console.WriteLine("PingDotNet needs a host or IP address, insert one");
address = Console.ReadLine();
Console.WriteLine();
}
else
{
address = args[0];
}
if (IsOffline())
{
Console.WriteLine("No internet connection detected.");
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
return;
}
IPAddress ip = null;
try
{
ip = Dns.GetHostEntry(address).AddressList[0];
}
catch (System.Net.Sockets.SocketException ex)
{
Console.WriteLine("DNS Error: {0}", ex.Message);
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
return;
}
Console.WriteLine("Pinging {0} [{1}] with 32 bytes of data:",
address, ip.ToString());
Console.WriteLine();
Thread pingThread = new Thread(new ParameterizedThreadStart(StartPing));
pingThread.Start(ip);
pingThread.Join();
}