c#编写的PING工具

www.chinacs.net 2001-4-27 16:06:00 中文C#技术站

导 读: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[i] = (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[i] =
                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 
}
Contributors: FHL