Send Multiple Pings - SendAsync (To test multiple hosts connnectivity quickly)

soelknight

Member
Joined
Jul 6, 2007
Messages
8
Programming Experience
Beginner
Hey all, I am noob to VB.Net and most Object Orientated (OO) Programming. Mainly I have programmed with PHP and a small amount of JavaScript (AJAX), I am using VS 2005 Express (Visual Basic) because I don't know any better. I am an independant network consultant and am interested in pinging multiple hosts fast (but accurate). I have been playing around with threading which seems over my head. As well as sending things async which is ok but I am having troubles sending multiple pings at a time and dealing with the results in an effective manor.

My question:
Is there a good way to do this fast (but accurate) by sending multiple pings? I am not interested in getting status really about the ping except maybe RTT in MS and wether it worked or not.

My vision for this program (my ideal program):
-Grab an array of DNS names from a text file or something. Ex. server1, pc1, pc2, pc3, etc. (This part I can probably do with some time and googleing...)
-Send all the pings async and at the same time. (I have googleed the heck out of it and cannot find anything that works.)
-When the pings return with a success or failure, update multiple buttons (Why buttons, because it was easy to add on the form.) backcolor on my form to be red for failed and green for success.
-Maybe also having a label next to the button that updated with RTT in MS next to it. (This would just be nice.)

Things I have tried:
-My.Computer.Network.Ping(hostname) <-- which is slow and blocking (i hope this is the right termm, I mean sending them in sync).
-Ping.SendAsync(hostname, 300, WaitEvent) <-- this is much quicker but I cannot seem to get multiple to send without blocking the responses so the next one sends when the first one has been returned.
- I have tried using the WMI to get some information but I cannot seem to get the correct level of access to the hosts to get anything useful and I am not sure if this was faster or not.

Sorry if I said some dumb stuff but I have searched and searched for weeks to months trying to figure this out, I appreciate any help or direction!
 
SendAsync/ I cannot seem to get multiple to send without blocking the responses so the next one sends when the first one has been returned.
What is the point of SendAsync when you want to wait for completion until pinging next? Maybe you want to async the whole batch and not each ping? If so you can use the BackgroundWorker and do the batch with Send for each in DoWork.
 
What is the point of SendAsync when you want to wait for completion until pinging next? Maybe you want to async the whole batch and not each ping? If so you can use the BackgroundWorker and do the batch with Send for each in DoWork.

Good point, I am clueless to be honest. I would love to send them all out in one shot and then when they come back I need them to update all the buttons to red or green depending on if they responded or not. I will look some information up on the BackgroundWorker process and DoWork.

Might you have some code to explain the BackgroundWorker process and DoWork? Just the general idea would be great!
 
Ok, comparing with your "vision" I might have misread that line, here's an example in accordance with the vision, I used a ListView (because it is easy to add to form and handle later, added 3 columns Server/Status/RTT)
VB.NET:
    Private d As New Dictionary(Of String, Ping)

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        ListView1.Items.Clear()
        For Each server As String In Regex.Split(My.Computer.FileSystem.ReadAllText("servers.txt"), vbNewLine)
            Dim p As New Ping
            d.Add(server, p)
            AddHandler p.PingCompleted, AddressOf p_PingCompleted
            p.SendAsync(server, 1000, server)
        Next
    End Sub

    Private Sub p_PingCompleted(ByVal sender As Object, ByVal e As System.Net.NetworkInformation.PingCompletedEventArgs)
        Dim server As String = e.UserState
        Dim lvi As ListViewItem = ListView1.Items.Add(server)
        lvi.SubItems.Add(e.Reply.Status.ToString)
        lvi.SubItems.Add(e.Reply.RoundtripTime.ToString)
        If e.Reply.Status = IPStatus.Success Then
            lvi.BackColor = Color.Green
        Else
            lvi.BackColor = Color.Red
        End If
        DirectCast(d(server), IDisposable).Dispose()
        d.Remove(server)
    End Sub
The servers.txt is a plain text file with one server listed each line, no empty lines.

Edit: add these imports or qualify the objects with these namespaces:
VB.NET:
Imports System.Net.NetworkInformation
Imports System.Text.RegularExpressions
 
Last edited:
So close!

K here is the scoop now... I copy and pasted your code directly into my VS2005. Created a Button and placed it on the form. Created a ListView and placed it on the form. Left the names alone. On the ListView I did "edit columns" and added three columns. Changed the text on each column, one to server, another to status, and the last to RTT. There are a couple of errors I am getting when I attempt to run it.

Errors I got when I copy and pasted the code, and my noob attempts to fix it:
-There is a wavy line under "Regex" when I put my cursor on it, it says "Name Regex is not declared". I added a line "Dim Regex" right under "Public Class Form1".
-There is a wavy line under "IPStatus", I changed that to "Net.NetworkInformation.IPStatus.Success", that seems to resolved that.
-As soon as I did the above bullet point it created a wavy line under "Ping" so I changed that to "Net.NetworkInformation.Ping", that seemed to resolve that.
-I ran it and it complained about the file location of servers.txt, more exact "Could not find file 'C:\Documents and Settings\<userid>\My Documents\Visual Studio 2005\Projects\testdrive\testdrive\bin\Debug\servers.txt'."
-1)I attempted to add a text file to the project as servers.txt, same error.
-2)I attempted to replace the file name "servers.txt" with the absolute path to the file, NEW!!! error this time was "Object variable or With block variable not set." ***I have no clue what this means or how to resolve this part of it.***
 
Oh, sorry about that, I had these Imports in my form without noticing it:
VB.NET:
Imports System.Net.NetworkInformation
Imports System.Text.RegularExpressions
I also added Disposing of Ping instances to the original code, should prevent possible memory leaks.
 
Ok that worked prefectly to run it! The only problem now is the output is kinda funky. In the ListView it is showing just the hostname... I got that fixed by having the view be "Details" and now I have column headings, etc. JohnH thanks for all your help! If I think of anything else I will post it here, thanks again, it works fast!
 
fixed by having the view be "Details" and now I have column headings
"Details-view" was yet another thing I forgot to mention, talking about 'columns' it is the only way the ListView can be configured and is something one do without thinking, but for the absolute beginner this may not be immediately obvious.

It's more or less the same with the imports, when an object type from pasted code is unknown to the IDE you get errors and squiggly lines and if you know about this you just search up where it belongs in the Framework library and qualify them or add Imports, I still always try to make my posted code copy-paste-ready or explain imports but this one slipped through as I somehow already had those imports there and didn't think about it.

The filename is another one, filename without path means relative to application executable if not current directory changes, for debug configuration it is project\bin\Debug\. Typical slackware debugging code and should have been an absolute path like "c:\servers.txt" or at least something like:
VB.NET:
Dim filepath As String = IO.Path.Combine(Application.StartupPath, "servers.txt")
There is more too, remember this is only an example to see how the pings could be send asynchronous and results presented. What if you used this setup and user clicked several times on the button, the code would break if not all pings already was finished because of the Dictionary key would be the same and it can't be. Maybe you want let those not finished linger and only resubmit new/finished ones, perhaps you would clear everything and cancel pings still working, maybe a whole different approach. Maybe using a button to start the pings isn't at all what you had in mind, but this is how forum examples work, they usually only provide clues to usage and possibly enough to get you started so you can write your application.
 
Now I am having some trouble, when I put a DNS name of a device the system cannot find it is throwing an innerexception, I am unsure how to properly handle this, I assume a try catch thingy, but where should it go in the code? Now it is working to detect wether the device pings or not it is just when it cannot resolve the host name on the ping.
 
You can check if e.Error is Nothing in PingCompleted event, if it isn't that means the call has thrown an exception.
VB.NET:
If e.Error Is Nothing Then
[COLOR="DarkGreen"]'ok, check status[/COLOR]
Else
[COLOR="Red"]'exception happened[/COLOR]
End If
 
Ok, comparing with your "vision" I might have misread that line, here's an example in accordance with the vision, I used a ListView (because it is easy to add to form and handle later, added 3 columns Server/Status/RTT)
VB.NET:
    Private d As New Dictionary(Of String, Ping)

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        ListView1.Items.Clear()
        For Each server As String In Regex.Split(My.Computer.FileSystem.ReadAllText("servers.txt"), vbNewLine)
            Dim p As New Ping
            d.Add(server, p)
            AddHandler p.PingCompleted, AddressOf p_PingCompleted
            p.SendAsync(server, 1000, server)
        Next
    End Sub

    Private Sub p_PingCompleted(ByVal sender As Object, ByVal e As System.Net.NetworkInformation.PingCompletedEventArgs)
        Dim server As String = e.UserState
        Dim lvi As ListViewItem = ListView1.Items.Add(server)
        lvi.SubItems.Add(e.Reply.Status.ToString)
        lvi.SubItems.Add(e.Reply.RoundtripTime.ToString)
        If e.Reply.Status = IPStatus.Success Then
            lvi.BackColor = Color.Green
        Else
            lvi.BackColor = Color.Red
        End If
        DirectCast(d(server), IDisposable).Dispose()
        d.Remove(server)
    End Sub
The servers.txt is a plain text file with one server listed each line, no empty lines.

Edit: add these imports or qualify the objects with these namespaces:
VB.NET:
Imports System.Net.NetworkInformation
Imports System.Text.RegularExpressions

thank you for this fastest ping i ever seen

i have one more question..
i have labels on form
every label have a name of location of my company wan
i need label(x).backcolor red color or green color or orange color ref to ping result status
can you help me plz?
thank you again
good luck
 
Back
Top