利用Visual C#实现ICMP网络协议

来源:互联网 发布:东莞淘宝培训 编辑:程序博客网 时间:2024/05/16 15:06

利用Visual C#实现ICMP网络协议

http://dev.rdxx.com/NET/CSharp/2007/12/311884755908.shtml

关键词: 网络协议 , Visual C# , ICMP , 网络 , 协议 , C# , CMP
。表01和表02是Socket类中的常用属性和方法及其简要说明。

属性 说明 AddressFamily 获取Socket的地址族。 Available 获取已经从网络接收且可供读取的数据量。 Blocking 获取或设置一个值,该值指示Socket是否处于阻塞模式。 Connected 获取一个值,该值指示Socket是否已连接到远程资源。 Handle 获取Socket的操作系统句柄。 LocalEndPoint 获取本地终结点。 ProtocolType 获取Socket的协议类型。 RemoteEndPoint 获取远程终结点。 SocketType 获取Socket的类型。 表01: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

 

六.Visual C#实现Ping命令的实现步骤

  下面是Visual C#实现Ping命令的具体实现步骤:

  1. 启动Visual Studio .net。

  2. 选择菜单【文件】|【新建】|【项目】后,弹出【新建项目】对话框。

  3. 将【项目类型】设置为【Visual C#项目】。

  4. 将【模板】设置为【Windows应用程序】。

  5. 在【名称】文本框中输入【Visual C#实现Ping命令】。

  6. 在【位置】的文本框中输入【E:/VS.net项目】,然后单击【确定】按钮,具体如图05所示:


图05:【Visual C#实现Ping命令】项目的【新建项目】对话框

  7. 【解决方案资源管理器】窗口中,双击Form1.cs文件,进入Form1.cs文件的编辑界面。

  8. 在Form1.cs文件的开头的导入命名空间的代码区,添加下列代码,下列代码是导入下面程序中使用到的类所在的命名空间:

using System.Net ;
using System.Net.Sockets ;
  9. 把Visual Studio .Net的当前窗口切换到【Form1.cs(设计)】窗口,并从【工具箱】中的【Windows窗体组件】选项卡中拖入下列组件到设计窗体,并执行相应的操作:

  一个TextBox组件,用来输入进行Ping操作的远程主机名称或IP地址。

  一个ListBox组件,用以显示Ping操作结果。

  一个Label组件。

  一个Button组件,名称为button1,并在它拖入窗体后,双击它,则Visual Studio .Net会在Form1.cs文件中产生其Click事件对应的处理代码。

  10. 把Visual Studio .Net的当前窗口切换到Form1.cs的代码编辑窗口,并用下列代码替换Form1.cs中的InitializeComponent过程对应的处理代码:

private void InitializeComponent ( )
{
this.textBox1 = new System.Windows.Forms.TextBox ( ) ;
this.label1 = new System.Windows.Forms.Label ( ) ;
this.listBox1 = new System.Windows.Forms.ListBox ( ) ;
this.button1 = new System.Windows.Forms.Button ( ) ;
this.SuspendLayout ( ) ;
this.textBox1.Location = new System.Drawing.Point ( 116 , 14 ) ;
this.textBox1.Name = "textBox1" ;
this.textBox1.Size = new System.Drawing.Size ( 148 , 21 ) ;
this.textBox1.TabIndex = 0 ;
this.textBox1.Text = "" ;
this.textBox1.TextChanged += new System.EventHandler ( this.textBox1_TextChanged ) ;
this.label1.Location = new System.Drawing.Point ( 12 , 14 ) ;
this.label1.Name = "label1" ;
this.label1.TabIndex = 1 ;
this.label1.Text = "请输入主机名:" ;
this.listBox1.BackColor = System.Drawing.SystemColors.WindowText ;
this.listBox1.ForeColor = System.Drawing.SystemColors.Window ;
this.listBox1.ItemHeight = 12 ;
this.listBox1.Location = new System.Drawing.Point ( 6 , 42 ) ;
this.listBox1.Name = "listBox1" ;
this.listBox1.Size = new System.Drawing.Size ( 400 , 280 ) ;
this.listBox1.TabIndex = 2 ;
this.button1.Location = new System.Drawing.Point ( 274 , 12 ) ;
this.button1.Name = "button1" ;
this.button1.TabIndex = 3 ;
this.button1.Text = "Ping" ;
this.button1.Click += new System.EventHandler ( this.button1_Click ) ;
this.AutoScaleBaseSize = new System.Drawing.Size ( 6 , 14 ) ;
this.ClientSize = new System.Drawing.Size ( 410 , 333 ) ;
this.Controls.AddRange ( new System.Windows.Forms.Control[ ] {
this.button1 ,
this.listBox1 ,
this.label1 ,
this.textBox1 } ) ;
this.MaximizeBox = false ;
this.Name = "Form1" ;
this.Text = "Visual C#实现Ping" ;
this.ResumeLayout ( false ) ;
}
  
原创粉丝点击