编写自己的PING工具

编写自己的PING工具


Author:&;nbspFrom:Internet


                编写自己的PING工具
   
  导 读:PING 是一个用来检测网络连接速度的使用工具,下面的文章将介绍在C#中利用System.Net.Sockets 来创建一个自己的PING 工具。
  --------------------------------------------------------------------------------
  PING 是一个用来检测网络连接速度的工具,它会在本机和给出的远程主机名之间建立一个SOCKET 连接并向其发送一个ICMP协议格式的数据包,然后远程主机作出响应,发回一个数据包,通过计算发送到接收数据包的时间间隔,我们可以确定连接的速度。
 
  使用方法 ping <hostname> [/r]
  <hostname> 主机名
  [/r] 可选属性,决定是否连续的 ping 远程主机。
 
  下面是代码:
  ///ping.cs
  namespace SaurabhPing
  {
    using System;
    using System.Net;
    using System.Net.Sockets;
    /// <summary>
    /// 主要的类:ping
    /// </summary>
    class Ping
    {
      //声明几个常量
      const int SOCKET_ERROR = -1;       
      const int ICMP_ECHO = 8;
      /// <summary>
      /// 这里取得Hostname参数
      /// </summary>
      public static void Main(string[] argv)
      {
        if(argv.Length==0)
        {
  //If user did not enter any Parameter inform him
  Console.WriteLine("Usage:Ping <hostname> /r") ;
  Console.WriteLine("<hostname> The name of the Host who you want to ping");
  Console.WriteLine("/r Ping the host continuously") ;
        }
        else if(argv.Length==1)
        {
  //Just the hostname provided by the user
  //call the method "PingHost" and pass the HostName as a parameter
  PingHost(argv[0]) ;
        }
        else if(argv.Length==2)
        {
  //the user provided the hostname and the switch
  if(argv[1]=="/r")
  {
    //loop the ping program
    while(true)
    {
  //call the method "PingHost" and pass the HostName as a parameter
  PingHost(argv[0]) ;
    }
          }
  else
  {
    //if the user provided some other switch
    PingHost(argv[0]) ;
  }
        }
        else
        {
  //Some error occurred
  Console.WriteLine("Error in Arguments") ;
          }
      }
 
        /// <summary>
        /// 主要的方法,用来取得IP,
        /// 并计算响应时间
        /// </summary>
        public static void PingHost(string host)
        {
  //Declare the IPHostEntry
  IPHostEntry serverHE, fromHE;
  int nBytes = 0;
  int dwStart = 0, dwStop = 0;
  //Initilize a Socket of the Type ICMP
  Socket socket =
  new Socket(AddressFamily.AfINet, SocketType.SockRaw, ProtocolType.ProtICMP);
 
  // Get the server endpoint
  try
  {
    serverHE = DNS.GetHostByName(host);
  }
  catch(Exception)
  {
    Console.WriteLine("Host not found"); // fail
    return ;
  }
 
  // Convert the server IP_EndPoint to an EndPoint
  IPEndPoint ipepServer = new IPEndPoint(serverHE.AddressList[0], 0);
  EndPoint epServer = (ipepServer);
 
  // Set the receiving endpoint to the client machine
  fromHE = DNS.GetHostByName(DNS.GetHostName());
  IPEndPoint ipEndPointFrom = new IPEndPoint(fromHE.AddressList[0], 0);       
  EndPoint EndPointFrom = (ipEndPointFrom);
 
  int PacketSize = 0;
  IcmpPacket packet = new IcmpPacket();
  // Construct the packet to send
  packet.Type = ICMP_ECHO; //8
  packet.SubCode = 0;
  packet.CheckSum = UInt16.Parse("0");
  packet.Identifier  = UInt16.Parse("45");
  packet.SequenceNumber  = UInt16.Parse("0");
  int PingData = 32; // sizeof(IcmpPacket) - 8;
  packet.Data = new Byte[PingData];
  //Initilize the Packet.Data
  for (int i = 0; i < PingData; i  )
  {
    packet.Data = (byte)'#';
  }
             
  //Variable to hold the total Packet size
  PacketSize = PingData  8;
  Byte [] icmp_pkt_buffer = new Byte[ PacketSize ];
  Int32 Index = 0;
  //Call a Method Serialize which counts
  //The total number of Bytes in the Packet
  Index = Serialize( 
                    packet,
                  icmp_pkt_buffer,
                    PacketSize,
                    PingData );
  //Error in Packet Size
  if( Index == -1 )
  {
    Console.WriteLine("Error in Making Packet");
    return ;
  }
           
  // now get this critter into a UInt16 array
         
  //Get the Half size of the Packet
  Double double_length = Convert.ToDouble(Index);
  Double dtemp = Math.Ceil( double_length / 2);
  int cksum_buffer_length = Convert.ToInt32(dtemp);
  //Create a Byte Array
  UInt16 [] cksum_buffer = new UInt16[cksum_buffer_length];
  //Code to initialize the Uint16 array
  int icmp_header_buffer_index = 0;
  for( int i = 0; i < cksum_buffer_length; i  ) {
    cksum_buffer =
          BitConverter.ToUInt16(icmp_pkt_buffer,icmp_header_buffer_index);
    icmp_header_buffer_index  = 2;
  }
  //Call a method which will return a checksum           
  UInt16 u_cksum = checksum(cksum_buffer, cksum_buffer_length);
  //Save the checksum to the Packet
  packet.CheckSum  = u_cksum;
             
  // Now that we have the checksum, serialize the packet again
  Byte [] sendbuf = new Byte[ PacketSize ];
  //again check the packet size
  Index = Serialize( 
                    packet,
                    sendbuf,
                    PacketSize,
                    PingData );
  //if there is a error report it
  if( Index == -1 )
  {
    Console.WriteLine("Error in Making Packet");
    return ;
  }
                 
 
  dwStart = System.Environment.TickCount; // Start timing
  //send the Pack over the socket
  if ((nBytes = socket.SendTo(sendbuf, PacketSize, 0, epServer)) == SOCKET_ERROR)
  {
    Console.WriteLine("Socket Error cannot Send Packet");
  }
  // Initialize the buffers. The receive buffer is the size of the
  // ICMP header plus the IP header (20 bytes)
  Byte [] ReceiveBuffer = new Byte[256];
  nBytes = 0;
  //Receive the bytes
  bool recd =false ;
  int timeout=0 ;
 
  //loop for checking the time of the server responding
  while(!recd)
  {
    nBytes = socket.ReceiveFrom(ReceiveBuffer, 256, 0, ref EndPointFrom);
    if (nBytes == SOCKET_ERROR)
    {
      Console.WriteLine("Host not Responding") ;
      recd=true ;
      break;
    }
    else if(nBytes>0)
    {
      dwStop = System.Environment.TickCount - dwStart; // stop timing
      Console.WriteLine("Reply from " epServer.ToString() " in "
  dwStop "MS :Bytes Received" nBytes);
      recd=true;
      break;
    }
    timeout=System.Environment.TickCount - dwStart;
    if(timeout>1000)
    {
      Console.WriteLine("Time Out") ;
      recd=true;
    }
          }
             
  //close the socket
  socket.Close();   
        }
        /// <summary>
        ///  This method get the Packet and calculates the total size
        ///  of the Pack by converting it to byte array
        /// </summary>
        public static Int32 Serialize(IcmpPacket packet, Byte[] Buffer,
  Int32 PacketSize, Int32 PingData )
        {
  Int32 cbReturn = 0;
  // serialize the struct into the array
  int Index=0;
 
  Byte [] b_type = new Byte[1];
  b_type[0] = (packet.Type);
 
  Byte [] b_code = new Byte[1];
  b_code[0] = (packet.SubCode);
 
  Byte [] b_cksum = BitConverter.GetBytes(packet.CheckSum);
  Byte [] b_id = BitConverter.GetBytes(packet.Identifier);
  Byte [] b_seq = BitConverter.GetBytes(packet.SequenceNumber);
         
  // Console.WriteLine("Serialize type ");
  Array.Copy( b_type, 0, Buffer, Index, b_type.Length );
  Index  = b_type.Length;
         
  // Console.WriteLine("Serialize code ");
  Array.Copy( b_code, 0, Buffer, Index, b_code.Length );
  Index  = b_code.Length;
 
  // Console.WriteLine("Serialize cksum ");
  Array.Copy( b_cksum, 0, Buffer, Index, b_cksum.Length );
  Index  = b_cksum.Length;
 
  // Console.WriteLine("Serialize id ");
  Array.Copy( b_id, 0, Buffer, Index, b_id.Length );
  Index  = b_id.Length;
 
  Array.Copy( b_seq, 0, Buffer, Index, b_seq.Length );
  Index  = b_seq.Length;
 
  // copy the data       
  Array.Copy( packet.Data, 0, Buffer, Index, PingData );
  Index  = PingData;
  if( Index != PacketSize/* sizeof(IcmpPacket)  */) {
    cbReturn = -1;
    return cbReturn;
  }
 
  cbReturn = Index;
  return cbReturn;
        }
        /// <summary>
        /// This Method has the algorithm to make a checksum
        /// </summary>
        public static UInt16 checksum( UInt16[] buffer, int size )
        {
  Int32 cksum = 0;
  int counter;
    counter = 0;
 
  while ( size > 0 ) {
            UInt16 val = buffer[counter];
 
    cksum  = Convert.ToInt32( buffer[counter] );
    counter  = 1;
    size -= 1;
  }
 
  cksum = (cksum >> 16)  (cksum &; 0xffff);
  cksum  = (cksum >> 16);
  return (UInt16)("cksum);
        }
      } // class ping
      /// <summary>
      /// Class that holds the Pack information
      /// </summary>
      public class IcmpPacket
      {
        public Byte  Type;    // type of message
        public Byte  SubCode;    // type of sub code
        public UInt16 CheckSum;  // ones complement checksum of struct
        public UInt16 Identifier;      // identifier
        public UInt16 SequenceNumber;    // sequence number 
        public Byte [] Data;
 
      } // class IcmpPacket
  }
 
 
    (2005-9-21:08:18)

 感谢原创者的辛勤劳动,希望对您有所帮助,转载请注明原出处。
 您可能对 [C#] 的这些文章也感兴趣:

C#中如何自定义事件?
WinForm App自动更新(Live Update)架构
C#锐利体验(1.2)
C# 网络资源
使用.NET实现你的IP切换器
设计模式之C#实现(三)FactoryMethod
C#和VB.NET版CLSA.NET 3.0电子图书面市
C#是什么?
ADO.NET深入研究(1)
C#中使用晚绑定实现压缩Access数据库