技术开发 频道

.NET Compact Framework下的Ping(ICMP)的开发

 【IT168技术文档】

 什么是 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] with 32 bytes of data:

 Request timed out.

 Request timed out.

 Reply from 222.92.117.56: bytes=32 time=360ms TTL=108

 Reply from 222.92.117.56: bytes=32 time=359ms TTL=108

 Ping statistics for 222.92.117.56:

 Packets: Sent = 4, Received = 2, Lost = 2 (50% loss),

 Approximate round trip times in milli-seconds:

 Minimum = 359ms, Maximum = 360ms, Average = 359ms

 ping的详细介绍可以参考这篇文章 http://en.wikipedia.org/wiki/Ping

 解决方案

 从上述的原理可知,对ping的开发其实就是对ICMP协议的开发。Internet Control Message Protocol (ICMP) 是网络层的协议,其负责网络主机之间的控制流信息,错误消息,路由信息以及其他数据的传输。关于 ICMP的详细介绍 可以参考这篇文章Internet Control Message Protocol (ICMP)

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

 IcmpCreateFile     生成发送ICMP请求的句柄。

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

 IcmpCloseHandle  关闭IcmpCreateFile生成的句柄。

 下面为这些API的P/Invoke

 [DllImport("iphlpapi.dll")]

 internal static extern IntPtr IcmpCreateFile();

 [DllImport("iphlpapi.dll")]

 internal static extern uint IcmpSendEcho2(IntPtr icmpHandle, IntPtr Event, IntPtr apcRoutine, IntPtr apcContext, uint ipAddress, IntPtr data, ushort dataSize, ref IPOptions options, IntPtr replyBuffer, uint replySize, uint timeout);

 [DllImport("iphlpapi")]

 internal static extern bool IcmpCloseHandle(IntPtr handle);

 通过参考Smart Device Framework 1.4源代码,我实现了一个Ping的封装类, Smart Device Framework 1.4可以在下面链接下载 http://www.opennetcf.com/Products/SmartDeviceFramework/tabid/65/Default.aspx

 public IcmpEchoReply Send(IPAddress address, int timeout)

 {

 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);

 uint ip = BitConverter.ToUInt32(address.GetAddressBytes(), 0);

 IPOptions option = new IPOptions(null as PingOptions);

 IcmpSendEcho2(handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ip, requestBuffer, (ushort)SendBuffer.Length, ref option, replyBuffer, 0xffff, (uint)timeout);

 if (requestBuffer != IntPtr.Zero)

 {

 LocalFree(requestBuffer);

 requestBuffer = IntPtr.Zero;

 }

 return Marshal.PtrToStructure(replyBuffer, typeof(IcmpEchoReply)) as IcmpEchoReply;

 }

 上面是发送ICMP请求的核心代码,代码的逻辑是 先生成一个ICMP句柄,为返回结果包分配内存,对发送包进行赋值。然后发送ICMP请求,并等待回应。当接收到回应时把回应的数据包赋值到IcmpEchoReply结构体里面。回应信息可以通过IcmpEchoReply结构体取出。IcmpEchoReply信息可参考下面的客户端代码。

 客户端

 IcmpEchoReply reply = ping.Send(ip);

 if (reply.status == (uint)IPStatus.Success)

 {

 IPAddress addr = new IPAddress(reply.address);

 ShowMessage(String.Format("Reply from {0}: Echo size={1} time<{2}ms TTL={3}", 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的结果。

 图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 (int i = 0; i < addressList.Length; ++i)

 {

 ShowMessage(String.Format("Pinging Host {0} [{1}]", uri, addressList[i]));

 Ping(addressList[i]);

 }

 }

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

 下面为ping www.google.com的例子,http://www.google.com/对应3个不同的IP。

 图2


查看原文地址

0
相关文章