Reputation: 112
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
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
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
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