How to Ping a computer using .NET Sockets

///
/// The main entry point for the application.
///
[STAThread]

static void Main(string[] args)
{

    int timeToReplyMs = Ping("andrewbaker.ninja", 10000);
    Console.WriteLine("Time Taken(ms): " + timeToReplyMs);
}




#region Ping Method
///
/// Pings a host and returns the time taken for the host to respond (given the host name or IP address of the host to ping).
///



/// The host (machine name or IP address) to ping.
/// The ping timeout in ms (zero represents infinite).
/// Returns the time in milliseconds to receive a response from the host.

public static int Ping(string host, int timeout)

{

    //IPHostEntry ipHost = Dns.GetHostByName(host);
    IPHostEntry ipHost = Dns.GetHostEntry(host);

    // Ping the server
    return Ping(ipHost, timeout);

}




///
/// Pings a host and returns the time taken for the host to respond.
///




/// The host to ping.
/// The ping timeout in ms (zero represents infinite).
/// Returns the time in milliseconds to receive a response from the host.

public static int Ping(IPHostEntry host, int timeout)

{

    // Declare some Constant Variables
    const int SOCKET_ERROR = -1;
    const int ICMP_ECHO = 8;
    int timeTaken;



    // Declare the IPHostEntry
    if (host == null)
    {
        throw new ArgumentNullException("host", "The host to ping must be specified.");
    }

    Socket socket = null;

    try

    {
        // Initilize a Socket of the Type ICMP
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);


        // Convert to the first Ip address from the host to an endpoint
        IPEndPoint ipepServer = new IPEndPoint(_GetValidAddress(host.AddressList), 0);
        EndPoint epServer = (ipepServer);

        // Set the receiving endpoint to the client machine
        IPHostEntry localHost;

        localHost = Dns.GetHostEntry(Dns.GetHostName());
        IPEndPoint ipEndPointFrom = new IPEndPoint(_GetValidAddress(localHost.AddressList), 0);
        EndPoint EndPointFrom = (ipEndPointFrom);


        int packetSize;

        IcmpPacket packet = new IcmpPacket();

        // Construct the echo packet
        packet.Type = ICMP_ECHO; //8
        packet.SubCode = 0;
        packet.CheckSum = UInt16.Parse("0");
        packet.Identifier = UInt16.Parse("45");
        packet.SequenceNumber = UInt16.Parse("0");

        int pingDataSize = 32; // sizeof(IcmpPacket) - 8;

        packet.Data = new Byte[pingDataSize];

        // Initilize the Packet.Data
        for (int i = 0; i < pingDataSize; i++)
        {
            packet.Data[i] = (byte)'#';
        }

        // Variable to hold the total Packet size
        packetSize = pingDataSize + 8;
        Byte[] icmpPacketBuffer = new Byte[packetSize];
        int totalPacketSize;


        // Call Serialize, which counts the total number of Bytes in the Packet
        totalPacketSize = _SerializePacket(packet, icmpPacketBuffer, packetSize, pingDataSize);


        // Error in Packet Size
        if (totalPacketSize == -1)
        {
            // Throw serialization exception
            throw new ApplicationException("Error serializing packet buffer");
        }

        // Get the packet into a UInt16 array
        // Get the Half size of the Packet
        Double packetSizeDouble = Convert.ToDouble(totalPacketSize);
        Double halfPacketSizeDouble = Math.Ceiling(packetSizeDouble / 2);
        int checkSumBufferLength = Convert.ToInt32(halfPacketSizeDouble);

        // Create a Byte Array
        UInt16[] checkSumBuffer = new UInt16[checkSumBufferLength];

        // Code to initilize the Uint16 array
        int icmpHeaderBufferIndex = 0;

        for (int i = 0; i < checkSumBufferLength; i++)
        {
            checkSumBuffer[i] = BitConverter.ToUInt16(icmpPacketBuffer, icmpHeaderBufferIndex);
            icmpHeaderBufferIndex += 2;

        }

        // Call a method which will return a checksum
        UInt16 unsignedCheckSum = _CalcChecksum(checkSumBuffer, checkSumBufferLength);

        // Save the checksum to the Packet
        packet.CheckSum = unsignedCheckSum;

        // Have the checksum, serialize the packet again
        Byte[] sendbuf = new Byte[packetSize];

        // Check the packet size
        totalPacketSize = _SerializePacket(packet, sendbuf, packetSize, pingDataSize);


        if (totalPacketSize == -1)
        {
            // Throw serialization exception
            throw new ApplicationException("Error serializing packet buffer");

        }


        // Start timing
        int dwStart = Environment.TickCount;

        // Send the Packet
        if (socket.SendTo(sendbuf, packetSize, 0, epServer) == SOCKET_ERROR)
        {
            throw new ApplicationException("Failed to send packet to " + host.HostName + ".");

        }


        // Initialize the buffers. The receive buffer is the size of the
        // ICMP header plus the IP header (20 bytes)
        Byte[] arrayBytesReceived = new Byte[256];


        // Loop for checking the time of the server responding
        while (true)

        {

            int nBytes = socket.ReceiveFrom(arrayBytesReceived, 256, 0, ref EndPointFrom);
            timeTaken = Environment.TickCount - dwStart;



            if (nBytes == SOCKET_ERROR)
            {

                throw new ApplicationException("Failed to receive response to echo packet from " + host.HostName + ".");

            }

            else if (nBytes > 0)

            {
                // Received message
                // int dwStop = Environment.TickCount - dwStart;
                // Console.WriteLine("Reply from " + epServer.ToString() + " in " + dwStop + "MS :Bytes Received" + nBytes);
                break;
            }




            // Default to a one second timeout
            if (timeTaken > timeout && timeout > 0)
            {
                throw new ApplicationException("Ping to " + host.HostName + " timed out after " + timeout + " milliseconds.");
            }
        }

    }
    finally
    {
        if (socket != null)
        {
            // close the socket
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
        }

    }




    return timeTaken;

}

//
// Find a valid IP address
private static IPAddress _GetValidAddress(IPAddress[] addressList)
{
    for (int i = 0; i < addressList.Length; i++)
    {
        try
        {
            var address = addressList[i].Address;
        }
        catch (Exception)
        {
            // Invalid address
            continue;
        }
        // The address is valid
        return addressList[i];
    }
    return null;
}



#region Private Methods

///
/// This method get the Packet and calculates the total size
/// of the Pack by converting it to byte array
///
private static int _SerializePacket(IcmpPacket packet, Byte[] Buffer, int PacketSize, int PingData)

{

    int cbReturn;

    // 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;
}

///
/// This Method has the algorithm to make a checksum
///
private static UInt16 _CalcChecksum(UInt16[] buffer, int size)

{
    int cksum = 0;
    int counter;

    counter = 0;

    while (size > 0)
    {
        UInt16 val = buffer[counter];
        cksum += Convert.ToInt32(val);
        counter += 1;
        size -= 1;
    }

    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);

    return (UInt16)(~cksum);

}

#endregion Private Methods




#region IcmpPacket Class (Private)

///
/// Class that holds the Pack information.
///
private class IcmpPacket
{

    ///
    /// Type of message
    ///
    public Byte Type;

    ///
    /// Type of sub code
    ///
    public Byte SubCode;

    ///
    /// Complement checksum of struct
    ///
    public UInt16 CheckSum;

    ///
    /// Identifier
    ///
    public UInt16 Identifier;

    ///
    /// Sequence number
    ///
    public UInt16 SequenceNumber;

    ///
    /// The data
    ///
    public Byte[] Data;

}

#endregion IcmpPacket Class (Private)

}

endregion

Leave a Reply

Your email address will not be published. Required fields are marked *