using System ;
using System.Drawing ;
using System.Collections ;
using System.ComponentModel ;
using System.Windows.Forms ;
using System.Data ;
using System.Net ;
using System.Net.Sockets ;
namespace WindowsApplication24
{
/// <summary>
/// Form1 的摘要说明。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1 ;
private System.Windows.Forms.TextBox textBox1 ;
private System.Windows.Forms.Button button1 ;
private System.Windows.Forms.ListBox listBox1 ;
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.Container components = null ;
public Form1 ( )
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent ( ) ;
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose ( bool disposing )
{
if ( disposing )
{
if ( components != null )
{
components.Dispose ( ) ;
}
}
base.Dispose ( disposing ) ;
}
#region Windows Form Designer generated code
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent ( )
{
this.label1 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.listBox1 = new System.Windows.Forms.ListBox();
this.SuspendLayout();
//
// label1
//
this.label1.Location = new System.Drawing.Point(11, 13);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(99, 25);
this.label1.TabIndex = 0;
this.label1.Text = "目的地址:";
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(94, 11);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(232, 21);
this.textBox1.TabIndex = 1;
//
// button1
//
this.button1.Location = new System.Drawing.Point(340, 9);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(68, 28);
this.button1.TabIndex = 2;
this.button1.Text = "Tracert";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// listBox1
//
this.listBox1.BackColor = System.Drawing.SystemColors.WindowText;
this.listBox1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.listBox1.ForeColor = System.Drawing.SystemColors.Window;
this.listBox1.ItemHeight = 12;
this.listBox1.Location = new System.Drawing.Point(0, 41);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(370, 304);
this.listBox1.TabIndex = 3;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(370, 345);
this.Controls.Add(this.listBox1);
this.Controls.Add(this.button1);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.label1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.Name = "Form1";
this.Text = "C#实现Tracert命令";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread ]
static void Main ( )
{
Application.Run ( new Form1 ( ) ) ;
}
private void button1_Click ( object sender , System.EventArgs e )
{
listBox1.Items.Clear ( ) ;
//清除Tracert命令的结果显示区
try
{
if ( textBox1.Text.Length == 0 )
{
listBox1.Items.Add ( "请输入目的地址!" ) ;
textBox1.Focus ( ) ;
return ;
}
Socket s = new Socket ( AddressFamily.InterNetwork , SocketType.Raw , ProtocolType.Icmp ) ;
//创建接收和发送ICMP报文的Socket
IPEndPoint ipDEST = new IPEndPoint ( Dns.Resolve ( textBox1.Text ) .AddressList [ 0 ] ,30 ) ;
// 设定服务器端30端口号对应的网络结点
IPEndPoint ipSRC = new IPEndPoint ( Dns.GetHostByName ( Dns.GetHostName ( ) ) .AddressList [ 0 ] ,30 ) ;
EndPoint epSRC = ( EndPoint ) ipSRC ;
int DataSize = 4 ; // ICMP报文中的“数据”长度“ ;
int PacketSize = DataSize + 8 ;//总报文长度
const int ICMP_ECHO = 8 ;
IcmpPacket packet = new IcmpPacket ( ICMP_ECHO , 0 , 0 , 45 , 0 , DataSize ) ;
Byte [ ] Buffer = new Byte [ PacketSize ] ;
int index = packet.CountByte ( Buffer ) ;
if ( index != PacketSize )
{
listBox1.Items.Add ( "报文出现问题!" ) ;
return ;
}
int cksum_buffer_length = ( int ) Math.Ceiling ( ( ( Double ) index ) / 2 ) ;
UInt16 [ ] cksum_buffer = new UInt16 [ cksum_buffer_length ] ;
int icmp_header_buffer_index = 0 ;
for ( int i = 0 ; i < cksum_buffer_length ; i++ )
{
//将两个byte转化为一个UInt16
cksum_buffer [ i ] = BitConverter.ToUInt16 ( Buffer , icmp_header_buffer_index ) ;
icmp_header_buffer_index += 2 ;
}
//将校验和保存至报文里
packet.CheckSum = IcmpPacket.SumOfCheck ( cksum_buffer ) ;
// 保存校验和后,再次将报文转化为数据包
Byte [ ] ByteSend = new Byte [ PacketSize ] ;
index = packet.CountByte ( ByteSend ) ;
//报文出错
if ( index != PacketSize )
{
listBox1.Items.Add ( "报文出现问题!" ) ;
return ;
}
//发送不同TTL值的数据包
for ( int ittl=1 ; ittl <= 255 ; ittl++ )
{
Byte [ ] ByteRecv = new Byte [ 256 ] ;
s.SetSocketOption ( SocketOptionLevel.IP , SocketOptionName.IpTimeToLive , ittl ) ;
s.SetSocketOption ( SocketOptionLevel.Socket , SocketOptionName.SendTimeout , 10000 ) ;
s.SetSocketOption ( SocketOptionLevel.Socket , SocketOptionName.ReceiveTimeout , 10000 ) ;
//设定TTL和超时信息
DateTime dt = DateTime.Now ;
//获得当前时间
int iRet = s.SendTo ( ByteSend , ByteSend.Length , SocketFlags.None , ipDEST ) ;
//发送ICMP报文
if ( iRet == -1 )
listBox1.Items.Add ( "发送数据出现错误!" ) ;
//接收返回数据
iRet = s.ReceiveFrom ( ByteRecv , ByteRecv.Length , SocketFlags.None , ref epSRC ) ;
//计算发送数据到接收数据之间的时间差
TimeSpan ts = DateTime.Now - dt ;
//检测回应是否正确
if ( iRet == -1 )
listBox1.Items.Add ( "接收数据出现错误!" ) ;
listBox1.Items.Add ( "TTL=" + ittl.ToString ( ) + " IP=" + ( ( IPEndPoint ) epSRC ) .Address.ToString ( ) + " Time= " + ts.Milliseconds.ToString ( ) ) ;
//判断是否到达目的地址
if ( Dns.Resolve ( textBox1.Text ) .AddressList [ 0 ] .ToString ( ) == ( ( IPEndPoint ) epSRC ) .Address.ToString ( ) )
{
break ;
}
//超时错误
if ( ByteRecv [ 20 ] != 11 )
{
listBox1.Items.Add ( "出现超时误,请重试!" ) ;
break ;
}
}
}
catch ( SocketException b )
{
MessageBox.Show ( b.Message ) ;
}
catch ( Exception ex )
{
MessageBox.Show ( ex.Message ) ;
}
}
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 ) ;
}
}
}
}
()