什么是 Ping Tester?

Ping Tester是一个网络侦测工具(Diagnostics),可以使用在Windows Mobile来检查网络的联通性。

简介

文本讲述了在.NET Compact Framework下ping功能的实现。 主要通过P/Invoke的方式调用ICMP相关的API来实现。 同时提供一个Windows Mobile的工具来调用Ping封装类。

背景

由于在3G网络下开发数据通信程序,需要验证该网络的连通性和可靠性,所以开发这个Ping封装类方便验证网络的可靠性。

原理

Ping(Packet InterNet Groper)是一个网络诊断工具,他的工作原理就是 发送ICMP的“echo request”

数据包到目标主机,然后监听ICMP的“echo response”回应数据包。 Ping通过度量反应时间(round-trip time,

RTT)和记录所有丢包情况等信息,产生一个统计报告。下面是我电脑ping博客园的例子,请大家看看本人的网络是如何的不可靠,生活在水深火热的中,写

Blog常常断网。

C:\>ping cnblogs.com
Pinging cnblogs.com [222.92.117.56] with32bytes of data:
Request timedout.
Request timedout.
Reply from222.92.117.56: bytes=32time=360ms TTL=108Reply from222.92.117.56: bytes=32time=359ms TTL=108Ping statisticsfor222.92.117.56:
Packets: Sent=4, Received=2, Lost=2(50%loss),
Approximate round trip timesinmilli-seconds:
Minimum=359ms, Maximum=360ms, Average=359ms

ping的详细介绍可以参考这篇文章

解决方案

从上述的原理可知,对ping的开发其实就是对ICMP协议的开发。Internet Control Message Protocol

(ICMP) 是网络层的协议,其负责网络主机之间的控制流信息,错误消息,路由信息以及其他数据的传输。关于 ICMP的详细介绍 可以参考这篇文章

进行ICMP的开发,主要有以下几个API:

生成发送ICMP请求的句柄。

发送ICMP请求,并得到回应信息。

关闭IcmpCreateFile生成的句柄。

下面为这些API的P/Invoke

[DllImport("iphlpapi.dll")]internalstaticexternIntPtr IcmpCreateFile();
[DllImport("iphlpapi.dll")]internalstaticexternuintIcmpSendEcho2(IntPtr icmpHandle, IntPtr Event, IntPtr apcRoutine, IntPtr apcContext,uintipAddress, IntPtr data,ushortdataSize,refIPOptions options, IntPtr replyBuffer,uintreplySize,uinttimeout);
[DllImport("iphlpapi")]internalstaticexternboolIcmpCloseHandle(IntPtr handle);

通过参考Smart Device Framework 1.4源代码,我实现了一个Ping的封装类, Smart Device Framework 1.4可以在下面链接下载

publicIcmpEchoReply Send(IPAddress address,inttimeout)
{if(handle==IntPtr.Zero)
{
handle=IcmpCreateFile();
}if(replyBuffer==IntPtr.Zero)
{
replyBuffer=LocalAlloc(LPTR, (uint)0xffff);
}
requestBuffer=LocalAlloc(LPTR, (uint)SendBuffer.Length);
Marshal.Copy(SendBuffer,0, requestBuffer, SendBuffer.Length);uintip=BitConverter.ToUInt32(address.GetAddressBytes(),0);
IPOptions option=newIPOptions(nullasPingOptions);
IcmpSendEcho2(handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ip, requestBuffer, (ushort)SendBuffer.Length,refoption, replyBuffer,0xffff, (uint)timeout);if(requestBuffer!=IntPtr.Zero)
{
LocalFree(requestBuffer);
requestBuffer=IntPtr.Zero;
}returnMarshal.PtrToStructure(replyBuffer,typeof(IcmpEchoReply))asIcmpEchoReply;
}

上面是发送ICMP请求的核心代码,代码的逻辑是

先生成一个ICMP句柄,为返回结果包分配内存,对发送包进行赋值。然后发送ICMP请求,并等待回应。当接收到回应时把回应的数据包赋值到

IcmpEchoReply结构体里面。回应信息可以通过IcmpEchoReply结构体取出。IcmpEchoReply信息可参考下面的客户端代

码。

客户端

IcmpEchoReply reply=ping.Send(ip);if(reply.status==(uint)IPStatus.Success)
{
IPAddress addr=newIPAddress(reply.address);
ShowMessage(String.Format("Reply from {0}: Echo size={1} time", addr, reply.dataSize, reply.roundTripTime, reply.ttl));
}else{
IPStatus ipStatus=(IPStatus)reply.status;
ShowMessage(String.Format("PING: transmit failed, error code {0}, {1}", reply.status.ToString(), ipStatus));
}

客户端调用的时候只需要调用Send()方法,然后分析IcmpEchoReply的结果。

icmp实现ping java icmp的ping_pingtester linux 源码

图1

为了提高可用性,增加对域名的支持。

IPAddress address=null;
IPAddress[] addressList=null;try{
address=IPAddress.Parse(uri);
}catch{try{
IPHostEntry entry=Dns.GetHostEntry(uri);
addressList=entry.AddressList;
}catch(Exception ex)
{
ShowMessage(String.Format("Ping request could not find host {0}. Please check the name and try again. {1}", textBoxAddress.Text, ex.Message));
}
}if(address!=null)
{
ShowMessage(String.Format("Pinging Host {0}", uri));
Ping(address);
}else{for(inti=0; i
{
ShowMessage(String.Format("Pinging Host {0} [{1}]", uri, addressList[i]));
Ping(addressList[i]);
}
}

当用户输入不是IP地址的时候,会对域名进行解释,把该域名的所对应的所有IP解释出来,存放到addressList里面,然后对每个IP进行Ping。

下面为ping 的例子,对应3个不同的IP。

icmp实现ping java icmp的ping_句柄_02

图2

运行环境:VS2008 + Windows Mobile 6 Professional SDK  + CF.NET 2.0