博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.NET Compact Framework下的Ping(ICMP)的开发
阅读量:7171 次
发布时间:2019-06-29

本文共 3965 字,大约阅读时间需要 13 分钟。

什么是 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的详细介绍可以参考这篇文章

 

解决方案

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

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

     生成发送ICMP请求的句柄。
   发送ICMP请求,并得到回应信息。
  关闭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可以在下面链接下载

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的例子,对应3个不同的IP。

图2

源代码:

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

 

转载地址:http://fhmwm.baihongyu.com/

你可能感兴趣的文章