Pinging multiple Stations as fast as possible

  1. 6 years ago

    Sascha S

    8 Apr 2014 Testers, Xojo Pro Germany, Lower Saxony

    Hello,

    i am working on some kind of network monitoring tool for Windows and Mac (not to be released). With this tool i need to ping 800+ stations as fast and as resource saving as possible. The online status of each station is populated in a Listbox.

    For this i have a dictionary with ip addresses as keys and the ping results as values. To make it Windows and OS X compatible, i use the Shell and the PING command. But i am open for any other cross platform solution.

    I do not want to slow down the GUI of my App, because it performs many other Tasks at the same time. User interactions are in most tasks involved.

    That's why i use a Thread which performs the PINGs and updates the dictionary. Plus a timer which checks each row in my Listbox (one column holds the ip addresses in the cell and the ping result in the celltags) and updates the celltags of the ip addresses column. The cellbackgroundpaint event then colors the rows dependent of the online/offline status.

    The following code is a quick and (VERY) dirty solution, i wrote just to get it to work. I am pretty sure it can be done much more elegant and smarter. If someone could please help me "optimizing" this code, i would be very happy. :)

      RunningThreads.Increase
      
      Dim IPAdressen(-1) As String
      Dim d As New Date
      Dim theShell1 As New Shell
      Dim theShell2 As New Shell
      Dim theShell3 As New Shell
      Dim theShell4 As New Shell
      Dim theShell5 As New Shell
      Dim theShell6 As New Shell
      
      #If TargetWin32 Then
        theShell1.Timeout = -1
        theShell2.Timeout = -1
        theShell3.Timeout = -1
        theShell4.Timeout = -1
        theShell5.Timeout = -1
        theShell6.Timeout = -1
      #EndIf
      
      theShell1.Mode = 2
      theShell2.Mode = 2
      theShell3.Mode = 2
      theShell4.Mode = 2
      theShell5.Mode = 2
      theShell6.Mode = 2
      
      PingeVerteilerNummer = PingResult.Count
      AnzahlPingTestDurchlaeufeBisher = AnzahlPingTestDurchlaeufeBisher + 1
      DauerLetzterDurchlauf = d.TotalSeconds-StartDesDurchlaufs
      StartDesDurchlaufs = d.TotalSeconds
      
      
      For Each Value As Variant In PingResult.Keys
        IPAdressen.Append Value.StringValue
      Next
      
      Dim x,y As Integer
      y = IPAdressen.Ubound
      
      For x = 0 To y Step 6
        PingeVerteilerNummer = PingeVerteilerNummer - 6
        
        If TargetWin32 Then
          theShell1.Execute "ping -n 1 -w 500 " + IPAdressen(x)
          If x+1<=y Then theShell2.Execute "ping -n 1 -w 500 " + IPAdressen(x+1)
          If x+2<=y Then theShell3.Execute "ping -n 1 -w 500 " + IPAdressen(x+2)
          If x+3<=y Then theShell4.Execute "ping -n 1 -w 500 " + IPAdressen(x+3)
          If x+4<=y Then theShell5.Execute "ping -n 1 -w 500 " + IPAdressen(x+4)
          If x+5<=y Then theShell6.Execute "ping -n 1 -w 500 " + IPAdressen(x+5)
        Else
          theShell1.Execute "ping -c 1 -t 1 " + IPAdressen(x)
          If x+1<=y Then theShell2.Execute "ping -c 1 -t 1 " + IPAdressen(x+1)
          If x+2<=y Then theShell3.Execute "ping -c 1 -t 1 " + IPAdressen(x+2)
          If x+3<=y Then theShell4.Execute "ping -c 1 -t 1 " + IPAdressen(x+3)
          If x+4<=y Then theShell5.Execute "ping -c 1 -t 1 " + IPAdressen(x+4)
          If x+5<=y Then theShell6.Execute "ping -c 1 -t 1 " + IPAdressen(x+5)
        End If
        
        Do
          App.DoEvents(40)
        Loop Until Not theShell1.IsRunning And Not theShell2.IsRunning And Not theShell3.IsRunning And Not theShell4.IsRunning And Not theShell5.IsRunning And Not theShell6.IsRunning
        
        If theShell1.Errorcode <> 0 Then
          // alert or handle ping failure
          PingResult.Value(IPAdressen(x)) = False
        Else
          PingResult.Value(IPAdressen(x)) = True
        End If
        
        If x+1<=y Then 
          If theShell2.Errorcode <> 0 Then
            // alert or handle ping failure
            PingResult.Value(IPAdressen(x+1)) = False
          Else
            PingResult.Value(IPAdressen(x+1)) = True
          End If
        End If
        
        If x+2<=y Then 
          If theShell3.Errorcode <> 0 Then
            // alert or handle ping failure
            PingResult.Value(IPAdressen(x+2)) = False
          Else
            PingResult.Value(IPAdressen(x+2)) = True
          End If
        End If
        
        If x+3<=y Then 
          If theShell4.Errorcode <> 0 Then
            // alert or handle ping failure
            PingResult.Value(IPAdressen(x+3)) = False
          Else
            PingResult.Value(IPAdressen(x+3)) = True
          End If
        End If
        
        If x+4<=y Then
          If theShell5.Errorcode <> 0 Then
            // alert or handle ping failure
            PingResult.Value(IPAdressen(x+4)) = False
          Else
            PingResult.Value(IPAdressen(x+4)) = True
          End If
        End If
        
        If x+5<=y Then
          If theShell6.Errorcode <> 0 Then
            // alert or handle ping failure
            PingResult.Value(IPAdressen(x+5)) = False
          Else
            PingResult.Value(IPAdressen(x+5)) = True
          End If
        End If
        
        If AppIsQuitting Then Exit
      Next
      
      RunningThreads.Decrease

    Use a pool of shells and in the Completed event of each shell, grab the next highest IP address and increment the count. Let it all run async. If you want to continue looping indefinitely, as soon as a shell hits the limit, it resets the next high to zero and it all starts over again.

  2. John H

    8 Apr 2014 Planet earth
    Edited 6 years ago

    Not because I want to kill your project. Since your are using ping, I just wonder maybe this application might be interesting as well:

    SmokePing
    http://oss.oetiker.ch/smokeping/

    Creates also graph and you can setup email alerts

    Demo: http://oss.oetiker.ch/smokeping-demo/?target=Customers.OP

  3. Sascha S

    8 Apr 2014 Testers, Xojo Pro Germany, Lower Saxony

    @John H Not because I want to kill your project. Since your are using ping, I just wonder maybe this application might be interesting as well:

    SmokePing
    http://oss.oetiker.ch/smokeping/

    Creates also graph and you can setup email alerts

    Demo: http://oss.oetiker.ch/smokeping-demo/?target=Customers.OP

    Thank you John, but the "Network Monitoring" is just a very small part of a bigger Project.
    But i will keep your recommendation. Maybe i can use it later for another project. :)

  4. Matthew C

    8 Apr 2014 Testers Roanoke, VA - Spartanburg, SC

    Are the IP's static in the case of the systems or dynamic within a particular range?

  5. Sascha S

    8 Apr 2014 Testers, Xojo Pro Germany, Lower Saxony

    @MatthewCombatti Are the IP's static in the case of the systems or dynamic within a particular range?

    Static

  6. John H

    8 Apr 2014 Planet earth

    Why do you not create an array of shells:

    Dim theShell(6) As Shell
    
    For i as Integer = 0 to ubound(theShell)
             theShell(i)  = New Shell
    Next
    
    // And the same when you want to execute the shells
    
    For i as Integer = 0 to ubound(theShell)
             theShell(i).execute(Command Array)
    Next
    
     
  7. Sascha S

    8 Apr 2014 Testers, Xojo Pro Germany, Lower Saxony

    @John H Why do you not create an array of shells:

    I can't because the amount of stations is unknown until i queried a few Servers. And arrays can only be dimensioned from constants or values, not variables.

  8. Norman P

    8 Apr 2014 Xojo Inc, Xojo Pro Seeking work. npalardy@great-w...

    @SaschaSchneppmueller I can't because the amount of stations is unknown until i queried a few Servers. And arrays can only be dimensioned from constants or values, not variables.

    Redim it based on the value you get ?

    dim i as integer = 123
    dim a(i) as integer

    i = 656

    redim a(i)

    Done

  9. Sascha S

    8 Apr 2014 Testers, Xojo Pro Germany, Lower Saxony

    @Norman P Redim it based on the value you get ?

    Thank you Norman :)

    But it looks like there's another issue. If i open 1000 Shells at once and start a Ping, i "loose the connection" to the Shells after i quierried 200 or so shells. Because after a certain amount of

    Do
    ...
    theShell(i).IsRunning
    ...
    Loop Until ...

    The Value of Shell(i).IsRunning is always "True" ?

  10. Norman P

    8 Apr 2014 Xojo Inc, Xojo Pro Seeking work. npalardy@great-w...

    I'd be amazed if you could open 100 terminal windows and ping that many sites all at once at any rate
    Never mind trying to do it from within Xojo
    I'd guess there's some resource limits that will impede this effort

  11. Matthew C

    8 Apr 2014 Testers Roanoke, VA - Spartanburg, SC

    I started an example for you here:

    http://www.xojodevspot.com/fastping.xojo_binary_project

    and uncovered a strange bug in Xojo. Threading barely got started before the bug appeared. You'll notice upon opening the project all source code has been commented out, and it still will not execute or build. The problem happened after adding a dictionary to the properties (removing the dictionary does not fix the issue). Also noticed that before the problem began I had to add a listbox twice (deleting it the first time), as Xojo stated that there were multiple items with the same name and which one could not be determined (hadn't even added code or called an instance of the listbox anywhere in the code). First time ever any of these issues have appeared. Can you confirm or does the code work for you?

    Will each of the systems being pinged have Xojo applications on them? If so you could save yourself time using the ADController (AutoDiscovery) class, in which case each system will report over the network that it is "alive and well." It also reports when a system "goes down," or is turned off using the Error/MemberJoined/MemberLeft events. You could install a small service app on the systems to do the monitoring in this way. Otherwise, using the ping method you will have latency before realizing a system has gone down. Running Threaded shells is bound to keep the CPU active, and ADController is CPU friendly.

  12. Bob C

    8 Apr 2014 Beaverton, Oregon and sometime...

    Have you thought of just shelling out to nmap? It is cross platform and you can scan a whole subnet at once.

  13. Tim H

    8 Apr 2014 Answer Portland, OR USA

    Use a pool of shells and in the Completed event of each shell, grab the next highest IP address and increment the count. Let it all run async. If you want to continue looping indefinitely, as soon as a shell hits the limit, it resets the next high to zero and it all starts over again.

  14. Sascha S

    9 Apr 2014 Testers, Xojo Pro Germany, Lower Saxony
    Edited 6 years ago

    @MatthewCombatti You'll notice upon opening the project all source code has been commented out, and it still will not execute or build.

    Just add Window1 to the App DefaultWindow Property and it runs fine.

    @MatthewCombatti Will each of the systems being pinged have Xojo applications on them?

    No. The "stations" are WiMAX, nanStation and other Wireless DSL Servers.

  15. Sascha S

    9 Apr 2014 Testers, Xojo Pro Germany, Lower Saxony

    @Tim H Use a pool of shells and in the Completed event of each shell, grab the next highest IP address and increment the count. Let it all run async. If you want to continue looping indefinitely, as soon as a shell hits the limit, it resets the next high to zero and it all starts over again.

    Thank you Tim. This is a well working solution. I do not even need a Thread. And the Network "Scan" now runs approx. 10 times faster. I was shocked how fast it is.

    I have created a global Class of type Shell and create 10 instances of them. In the Completed event of the global Shell Class, i handle all the stuff like picking the next IP Adress, updating counters and so on.

  16. Lee P

    is not verified 9 Apr 2014 Hertfordshire, UK
    Edited 6 years ago

    What about devices that will not response to ICMP...? Not sure that sending RAW ping packets is the way to go.

    You could also as an alternative to the often unreliable "ping" method do arping/arp-scan which is very quick.

    1024 host arp-scanned in 4.181 seconds :) Yep that's fast ok

    -image-

    Just a thought.

  17. Matthew C

    10 Apr 2014 Testers Roanoke, VA - Spartanburg, SC

    Here is the fastest way I devised over the last 2 days. It involves adding an HTTPSOCKET to your window, then adding the "AuthorizationRequired" event with name and password to the router and uses a timer set at 1000 (1second periods).

    In the case of our netgear router, I created a string and using the Get method of the httpsocket, invoking "http://192.168.1.1/DEV_device.htm" which retrieves an HTML rendition of both wired and wireless devices attached to the network, IP's, stationname, and duration of time the system has been awake/online. I simply parsed out the needed information into a listbox's columns and set the cell back color by online/offline status. In all, you can make a request once a second and have live second-by-second updates.

  18. Sascha S

    10 Apr 2014 Testers, Xojo Pro Germany, Lower Saxony

    @MatthewCombatti Here is the fastest way I devised over the last 2 days. It involves adding an HTTPSOCKET to your window, then adding the "AuthorizationRequired" event with name and password to the router and uses a timer set at 1000 (1second periods).

    In the case of our netgear router, I created a string and using the Get method of the httpsocket, invoking "http://192.168.1.1/DEV_device.htm" which retrieves an HTML rendition of both wired and wireless devices attached to the network, IP's, stationname, and duration of time the system has been awake/online. I simply parsed out the needed information into a listbox's columns and set the cell back color by online/offline status. In all, you can make a request once a second and have live second-by-second updates.

    Thank you, but only WiMAX and nanoStations have a http component. There are Stations involved which are only reachable via a Winbox System.

    Tim's solution works fine for me. I reduced the Shells to 5 at a time and reduced the processor load to 60% in peak times. Because the machine on which my App runs is not used for much more, it's ok for me. :)

  19. John H

    12 Apr 2014 Planet earth
    Edited 6 years ago

    For windows you can also use the WMI Classes with use of OLEObject to ping your target.

    Below is an example: (works only from WIndows Vista and upwards)

      
    // Info
    // http://msdn.microsoft.com/en-us/library/aa394350%28v=vs.85%29.aspx
    // http://msdn.microsoft.com/en-us/library/aa394595%28v=vs.85%29.aspx
      
      Dim targetHost As String = "www.xojo.com"
      
      Dim locator, objWMIService, objsPings, objPingStatus  As OLEOBJECT
      Dim nobjPings as Integer
      
      //  Connect to WMI 
       locator = new oleObject("WbemScripting.SWbemlocator", true)
      
      Dim wmiServiceParams(2) as variant 
      wmiServiceParams(1) = "." 
      wmiServiceParams(2) = "root\cimv2"
      
      objWMIService= locator.invoke("ConnectServer", wmiServiceParams)
      
      // Run the WMI query
      objsPings = objWMIService.ExecQuery ("Select * From Win32_PingStatus where Address = '"+targetHost+"'")
      
      nobjPings = objsPings.count - 1
      
      For i as integer = 0 to nobjPings
        objPingStatus = objsPings.ItemIndex(i)   
    
    // ItemIndex() is not supported in Windows XP only from Windows Vista and upwards
        
        if objPingStatus.Value("StatusCode") <> Nil  Then
          
          Dim stringData As String
          
          stringData = "Address: "  + objPingStatus.Value("Address") + EndOfLine
          stringData = stringData + "StatusCode: " + objPingStatus.Value("StatusCode") + EndOfLine
          stringData = stringData + "BufferSize: " + objPingStatus.Value("BufferSize") + EndOfLine
          stringData = stringData + "ProtocolAddress: " + objPingStatus.Value("ProtocolAddress") + EndOfLine
          stringData = stringData + "ReplyInconsistency: " + objPingStatus.Value("ReplyInconsistency") + EndOfLine
          stringData = stringData + "ReplySize: " + objPingStatus.Value("ReplySize") + EndOfLine
          stringData = stringData + "ResolveAddressNames: " + objPingStatus.Value("ResolveAddressNames") + EndOfLine
          stringData = stringData + "ResponseTime: " + objPingStatus.Value("ResponseTime") + EndOfLine
          stringData = stringData + "ResponseTimeToLive: " + objPingStatus.Value("ResponseTimeToLive") + EndOfLine
          stringData = stringData + "Timeout: " + objPingStatus.Value("Timeout") + EndOfLine
          stringData = stringData + "TimestampRoute: " + objPingStatus.Value("TimestampRoute") + EndOfLine
          stringData = stringData + "TimeToLive: " + objPingStatus.Value("TimeToLive") + EndOfLine
          stringData = stringData + "TypeofService: " + objPingStatus.Value("TypeofService") + EndOfLine
          
          msgbox stringData
        Else
          Msgbox ("Target : "+objPingStatus.Value("Address")+EndOfLine + "did not respond")
        End If
        
      Next 
      
      locator = Nil
      
    exception err as oleexception
      msgbox err.message
  20. 9 months ago

or Sign Up to reply!