Gian Marco Te
Gian Marco Te

Reputation: 112

how to ping multiple ip adresses at the same time

I currently have code that gets a range of ip addresses (ex. 192.168.1.101 to 192.168.1.110) and pings them individually by using a for loop. the problem is that this takes too long, especially if the ping is unsuccessful. Is it a good idea to ping 10 ip addresses at the same time? I tried using a background worker and i am hesitating on using multiple background workers. This is my working code:

private void btnPingRange_Click(object sender, EventArgs e)
{
    Control.CheckForIllegalCrossThreadCalls = false;
    backgroundWorker1.RunWorkerAsync();
    UpdateControls(true);   
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    UpdateControls(false);
}
static uint str2ip(string ip)
{
    string[] octets = ip.Split('.');

    uint x1 = (uint)(Convert.ToByte(octets[0]) << 24);
    uint x2 = (uint)(Convert.ToByte(octets[1]) << 16);
    uint x3 = (uint)(Convert.ToByte(octets[2]) << 8);
    uint x4 = (uint)(Convert.ToByte(octets[3]));

    return x1 + x2 + x3 + x4;
}
static string ip2str(uint ip)
{
    string s1 = ((ip & 0xff000000) >> 24).ToString() + ".";
    string s2 = ((ip & 0x00ff0000) >> 16).ToString() + ".";
    string s3 = ((ip & 0x0000ff00) >> 8).ToString() + ".";
    string s4 = (ip & 0x000000ff).ToString();

    string ip2 = s1 + s2 + s3 + s4;
    return ip2;
} 
 public string GetMacAddress(string ipAddress)
{
    string macAddress = string.Empty;
    System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
    pProcess.StartInfo.FileName = "arp";
    pProcess.StartInfo.Arguments = "-a " + ipAddress;
    pProcess.StartInfo.UseShellExecute = false;
    pProcess.StartInfo.RedirectStandardOutput = true;
    pProcess.StartInfo.CreateNoWindow = true;
    pProcess.Start();
    string strOutput = pProcess.StandardOutput.ReadToEnd();
    string[] substrings = strOutput.Split('-');
    if (substrings.Length >= 8)
    {
        macAddress = substrings[3].Substring(Math.Max(0, substrings[3].Length - 2))
                 + "-" + substrings[4] + "-" + substrings[5] + "-" + substrings[6]
                 + "-" + substrings[7] + "-"
                 + substrings[8].Substring(0, 2);
        return macAddress;
    }

    else
    {
        return "not found";
    }
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{

    try
    {
        uint startIP = str2ip(txtFrom.Text);
        uint endIP = str2ip(txtTo.Text);
        DataTable pingResults = new DataTable();
        pingResults.Columns.Add("Date");
        pingResults.Columns.Add("IP Address");
        pingResults.Columns.Add("Mac Address");
        pingResults.Columns.Add("Result");
//slow part
        for (uint currentIP = startIP; currentIP <= endIP; currentIP++)
        {
            string thisIP = ip2str(currentIP);

            Ping ping = new Ping();
            PingReply pingReply = ping.Send(thisIP.ToString());


            var message = (pingReply.Status == IPStatus.Success) ? "On" : "Off";
            pingResults.Rows.Add(DateTime.Now.ToShortDateString(), thisIP.ToString(),GetMacAddress(thisIP), message.ToString());

        }
        dataGridView1.DataSource = pingResults;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}
private void UpdateControls(bool isVisible)
{
    if (isVisible)
    {
        panel1.Visible = true;
        pictureBox1.Refresh();
        pictureBox2.Refresh();
        groupBox1.Enabled = false;
        groupBox2.Enabled = false;
    }
    else
    {
        panel1.Visible = false;
        groupBox1.Enabled = true;
        groupBox2.Enabled = true;
    }
}

Upvotes: 1

Views: 3342

Answers (3)

Gian Marco Te
Gian Marco Te

Reputation: 112

To all who are encountering the same problem, I coded this (I used a Parallel.For loop):

 static uint str2ip(string ip)
    {
     //this converts the ip address from the textboxes to bytes
    string[] octets = ip.Split('.');
    uint x1 = (uint)(Convert.ToByte(octets[0]) << 24);
    uint x2 = (uint)(Convert.ToByte(octets[1]) << 16);
    uint x3 = (uint)(Convert.ToByte(octets[2]) << 8);
    uint x4 = (uint)(Convert.ToByte(octets[3]));
    return x1 + x2 + x3 + x4;
    }
  private volatile DataTable pingResults = new DataTable();
  //And I use str2ip in the button click event which contains this:
  private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
       {
            try
            {
                pingResults.Clear();
                uint startIP = str2ip(txtFrom.Text);
                uint endIP = str2ip(txtTo.Text);
                Parallel.For(startIP, endIP, index => pingIpAddress(ip2str(startIP++)));
                Thread.Sleep(1000);
                //for (uint currentIP = startIP; currentIP <= endIP; currentIP++)
                      //  {
                      //      string thisIP = ip2str(currentIP);
                      //      Thread myNewThread = new Thread(() => pingIpAddress(thisIP));
                      //      myNewThread.Start();

                      //  }
                dataGridView1.DataSource = pingResults;

            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("Exception {0} Trace {1}", ex.Message, ex.StackTrace));
            }
        }
        private void pingIpAddress(string ip3)
        {//this method is where I ping the IP addresses
            try
            {
            string ip2 = ip3;
            Ping ping = new Ping();
            PingReply pingReply = ping.Send(ip2.ToString());
            var message = (pingReply.Status == IPStatus.Success) ? "On" : "Off";
                lock (pingResults.Rows.SyncRoot)
                {
                    AddToDataTable(ip2, message);
                }
            }
            catch (Exception ex)
            {

                MessageBox.Show(String.Format("Exception {0} Trace {1}", ex.Message, ex.StackTrace));
            }
        }
        private void AddToDataTable(string ip2,string msg)
        {
            try
            {
                pingResults.Rows.Add(DateTime.Now.ToShortDateString(), ip2, GetMacAddress(ip2), msg.ToString(), GetMachineNameFromIPAddress(ip2));

            }
            catch (Exception)
            {

                throw;
            }
        }

Upvotes: 0

Rahvin47
Rahvin47

Reputation: 91

I run a program that pings 15000 machines in the network with threading. Funny enough I hardly see any network traffic, eventhough it pings/checks 200 systems per second.

Be careful! DataTable is not thread safe. I wrote a seperate method to lock the DataTable for each update.

public static void UpdateValue(DataRow dr, string property, object value)
    {
        Monitor.Enter(computerTable);
        try
        {

            dr[property] = value;

        }
        catch 
        {
            //Do something with errors
        }

        finally
        {

            Monitor.Exit(computerTable);

        }
    }

The system itself will determine how many backgroundworkers it should start. It will queue all of them at once and then start handling them according to system performance.

Upvotes: 1

Joshua Bakker
Joshua Bakker

Reputation: 2358

This is not possible. You can only ping at one IP each time. This is the same in CMD. You can't do ping 127.0.0.1 127.0.0.2 or with a ,.

A good idea is to - as some people suggested in the comments - use threading for it. There's no way to ping at multiple IPs in 1 ping 'command'.

Upvotes: 1

Related Questions