三.简介Visual C#实现Ping命令使用的类:
Visual C#实现Ping命令中涉及到很多的类,其中最重要的是Socket类。这是因为程序中发送含有ICMP报文的IP数据包,接收含有ICMP超时或 ICMP会显报文的IP数据包和设定IP数据包中的TTL数值都会使用到Socket类。表01和表02是Socket类中的常用属性和方法及其简要说明。
| 属性 | 说明 |
| AddressFamily | 获取Socket的地址族。 |
| Available | 获取已经从网络接收且可供读取的数据量。 |
| Blocking | 获取或设置一个值,该值指示Socket是否处于阻塞模式。 |
| Connected | 获取一个值,该值指示Socket是否已连接到远程资源。 |
| Handle | 获取Socket的操作系统句柄。 |
| LocalEndPoint | 获取本地终结点。 |
| ProtocolType | 获取Socket的协议类型。 |
| RemoteEndPoint | 获取远程终结点。 |
| SocketType | 获取Socket的类型。 |
| 方法 | 说明 |
| Accept | 创建新的Socket以处理传入的连接请求。 |
| BeginAccept | 开始一个异步请求,以创建新的Socket来接受传入的连接请求。 |
| BeginConnect | 开始对网络设备连接的异步请求。 |
| BeginReceive | 开始从连接的Socket中异步接收数据。 |
| BeginReceiveFrom | 开始从指定网络设备中异步接收数据。 |
| BeginSend | 将数据异步发送到连接的 |
| BeginSendTo | 向特定远程主机异步发送数据。 |
| Bind | 使Socket与一个本地终结点相关联。 |
| Close | 强制Socket连接关闭。 |
| Connect | 建立到远程设备的连接。 |
| EndAccept | 结束异步请求以创建新的Socket来接受传入的连接请求。 |
| EndConnect | 结束挂起的异步连接请求。 |
| EndReceive | 结束挂起的异步读取。 |
| EndReceiveFrom | 结束挂起的、从特定终结点进行异步读取。 |
| EndSend | 结束挂起的异步发送。 |
| EndSendTo | 结束挂起的、向指定位置进行的异步发送。 |
| GetSocketOption | 返回Socket选项的值。 |
| IOControl | 为Socket设置低级别操作模式。 |
| Listen | 将Socket置于侦听状态。 |
| Poll | 确定Socket的状态。 |
| Receive | 接收来自连接Socket的数据。 |
| ReceiveFrom | 接收数据文报并存储源终结点。 |
| Select | 确定一个或多个套接字的状态。 |
| Send | 将数据发送到连接的 |
| SendTo | 将数据发送到特定终结点。 |
| SetSocketOption | 设置Socket选项。 |
| Shutdown | 禁用某Socket上的发送和接收。 |
表02:Socket类的常用方法及其说明
其中包含六组异步方法,它们是:
·BeginAccept和EndAccept
·BeginConnect和EndConnect
·BeginReceive和EndReceive
·BeginReceiveFrom和EndReceiveFrom"
·BeginSend和EndSend
·BeginSendTo"和"EndSendTo
其功能分别相当于"Accept"、"Connect"、"Receive"、"ReceiveFrom"、"Send"和"SendTo"方法。
四.Visual C#实现Ping命令的关键步骤及其解决方法
根据Ping命令的执行过程,可以把Ping命令分成三个主要的步骤:
1. 定义ICMP报文。
2. 客户机发送封装ICMP回显请求报文的IP数据包。
3. 客户机接收封装ICMP应答报文的IP数据包。
解决了上述三个步骤,Visual C#实现Ping命令就基本可以完成了。下面是这三个步骤的具体的解决方法。
1. 定义ICMP报文:
根据图05所示的ICMP报文组成结构,定义了一个类--IcmpPacket类。IcmpPacket类通过实例化就能够得到ICMP报文。下面代码是定义IcmpPacket类:
public class IcmpPacket
{
private Byte _type ;
// 类型
private Byte _subCode ;
// 代码
private UInt16 _checkSum ;
// 校验和
private UInt16 _identifier ;
// 识别符
private UInt16 _sequenceNumber ;
// 序列号
private Byte [ ] _data ;
//选项数据
public IcmpPacket ( Byte type , Byte subCode , UInt16 checkSum , UInt16 identifier , UInt16 sequenceNumber , int dataSize )
{
_type = type ;
_subCode = subCode ;
_checkSum = checkSum ;
_identifier = identifier ;
_sequenceNumber = sequenceNumber ;
_data=new Byte [ dataSize ] ;
//在数据中,写入指定的数据大小
for ( int i = 0 ; i < dataSize ; i++ )
{
//由于选项数据在此命令中并不重要,所以你可以改换任何你喜欢的字符
_data [ i ] = ( byte )'#' ;
}
}
public UInt16 CheckSum
{
get
{
return _checkSum ;
}
set
{
_checkSum=value ;
}
}
//初始化ICMP报文
public int CountByte ( Byte [ ] buffer )
{
Byte [ ] b_type = new Byte [ 1 ] { _type } ;
Byte [ ] b_code = new Byte [ 1 ] { _subCode } ;
Byte [ ] b_cksum = BitConverter.GetBytes ( _checkSum ) ;
Byte [ ] b_id = BitConverter.GetBytes ( _identifier ) ;
Byte [ ] b_seq = BitConverter.GetBytes ( _sequenceNumber ) ;
int i = 0 ;
Array.Copy ( b_type , 0 , buffer , i , b_type.Length ) ;
i+= b_type.Length ;
Array.Copy ( b_code , 0 , buffer , i , b_code.Length ) ;
i+= b_code.Length ;
Array.Copy ( b_cksum , 0 , buffer ,i , b_cksum.Length ) ;
i+= b_cksum.Length ;
Array.Copy ( b_id , 0 , buffer , i , b_id.Length ) ;
i+= b_id.Length ;
Array.Copy ( b_seq , 0 , buffer , i , b_seq.Length ) ;
i += b_seq.Length ;
Array.Copy ( _data , 0 , buffer , i , _data.Length ) ;
i += _data.Length ;
return i ;
}
//将整个ICMP报文信息和数据转化为Byte数据包
public static UInt16 SumOfCheck ( UInt16 [ ] buffer )
{
int cksum = 0 ;
for ( int i = 0 ; i < buffer.Length ; i++ )
cksum += ( int ) buffer [ i ] ;
cksum = ( cksum >> 16 ) + ( cksum & 0xffff ) ;
cksum += ( cksum >> 16 ) ;
return ( UInt16 ) ( ~cksum ) ;
}
}
下列代码是利用IcmpPacket类来创建ICMP报文:
IcmpPacket packet = new IcmpPacket ( 0 , 0 , 0 , 45 , 0 , 4 ) ;
此代码定义的ICMP报文中的数据段长度为4个字节,所以整个ICMP报文长度为12个字节(即:8+4),而封装此ICMP报文的IP数据包长度就是 32个字节(即:8+4+20)。在后面介绍的程序中,从客户端发送的ICMP会显请求报文的数据长度为4个字节,但从服务器介绍到的数据却是32个字节的原因。
2. 发送封装ICMP回显请求报文的IP数据包:
发送IP数据包首先要创建一个能够发送封装ICMP回显请求报文的IP数据包Socket实例,然后调用此Socket实例中的"SendTo"方法就可以了。下列代码是创建并初始化一个发送封装ICMP回显请求报文的IP数据包的Socket实例:
Socket socket = new Socket ( AddressFamily.InterNetwork , SocketType.Raw , ProtocolType.Icmp ) ;
创建初始化Socket实例有三个参数,下面是这些参数的说明:
第一个参数定义目前网络的寻址方案,目前还是IPV4,所有只有定义为"AddressFamily.InterNetwork"。
第二个参数定义Socket实例的类型,由于Socket的通讯协议是ICMP,所以选择枚举值"Raw Socket"。
第三个参数是定义Socket实例有效的协议类型,由于此Socket实例要传送的是ICMP报文,所以选定枚举值为"ProtocolType.Icmp"。
3.客户机接收封装ICMP应答报文的IP数据包:
接收服务器端返回的封装ICMP应答报文的IP数据包只需调用Socket实例中的"ReceiveFrom"方法就可以了,具体可参阅下面介绍的程序实现中的代码。
五.Visual C#实现Ping命令的设计、调试、运行的软件环境:
(1).微软公司视窗2000服务器版
(2).Visual Studio .Net正式版,.Net FrameWork SDK版本号3705
