Jump to content

What's wrong with ping() (or with me)?


cherdeg
 Share

Recommended Posts

Suggestion:

- Run 10 ping commands at one time. The nice thing of having them in a different process is that you can do it asynchronously.

- Set parameters on the ping command to specify a number of repetitions and timeout.

- Check out the AutoIt source code, to see how the Ping() works in the underlying C++ code.

Link to comment
Share on other sites

Here. I didn't want to confuse you with what parts belong to the _MSPing "library" and what is part of the script using the library. So I didn't use any functions in the script that uses the library, was kind of a pain and I had to do stuff like ExitLoop 2 but I hope you still understand it.

#include <Constants.au3>
#include <Array.au3>


#cs
; Simple example:
$a_ping = _MSPing("localhost")
While (Not _MSPingIsReady($a_ping))
    Sleep(250)
WEnd
$pingtime = _MSPingGetResult($a_ping)
MsgBox(0,"", "Ping time: " & $pingtime)
#ce


; Async example

Local Const $MAX_PROCESS = 10 ; We spawn a maximum of 10 processes at once
Local $a_process[$MAX_PROCESS] ; An array to keep a reference to spawned processes, in the next loop we fill it with value 0
For $i = 0 to UBound($a_process)-1
    $a_process[$i] = 0
Next

; The following array represents a list of hosts, these are probably provided from a file later on
Local $address[100]
For $i = 0 to 99
    $address[$i] = "74.125.45." & $i+1 ; We generate some IPs
Next

ConsoleWrite("Pinging " & UBound($address) & " addresses." & @CRLF)

Local $i = 0 ; A pointer to run through the $address array
While True
    
    ; Check on the current processes, and look if there is one finished for use with our next host in line (from $address)
    For $n = 0 to UBound($a_process)-1
        If ($a_process[$n] == 0) Then ; Check if there is an empty spot
            ; There is an empty spot
            ConsoleWrite("Pinging " & $address[$i] & " ... " & @CRLF)
            $a_process[$n] = _MSPing($address[$i])
            
            $i += 1
            If ($i == UBound($address)) Then
                ExitLoop 2
            EndIf
        Else
            ; Something is running here, let's check on the output
            If (_MSPingIsReady($a_process[$n])) Then
                ; We have an output here, let's get it!
                $hostname = _MSPingGetHostname($a_process[$n])
                $pingtime = _MSPingGetResult($a_process[$n])
                If ($pingtime <> -1) Then
                    ConsoleWrite($hostname & " has a roundtrip of " & $pingtime & "." & @CRLF)
                Else
                    ConsoleWrite($hostname & " is unreachable." & @CRLF)
                EndIf
                
                ; Free up an empty space for the next address to Ping
                $a_process[$n] = 0
            EndIf
        EndIf
    Next
    
    Sleep(50) ; Give existing ping commands some time to process the request
WEnd

ConsoleWrite("Ping ready!!" & @CRLF)

Func _MSPing($hostname, $timeout = 50)
    Local $return_struc[4]
    ; [0] = Result (in ms)
    ; [1] = The hostname originally used
    ; [2] = Process handle (for internal use only)
    ; [3] = Buffer (for internal use only)
    
    $return_struc[1] = $hostname
    $return_struc[2] = Run("ping " & $hostname & " -n 1 -w " & $timeout, "", @SW_HIDE, $STDOUT_CHILD)
    
    Return $return_struc
EndFunc

Func _MSPingIsReady(ByRef $return_struc)
    Return ___MSPingReadOutput($return_struc)
EndFunc

Func _MSPingGetResult($return_struc)
    Return $return_struc[0]
EndFunc

Func _MSPingGetHostname($return_struc)
    Return $return_struc[1]
EndFunc

; Internal use only
Func ___MSPingReadOutput(ByRef $return_struc)
    $data = StdoutRead($return_struc[2])
    If (@error) Then
        ___MSPingParseResult($return_struc)
        Return 1
    Else
        $return_struc[3] &= $data
        Return 0
    EndIf
EndFunc

; Internal use only
Func ___MSPingParseResult(ByRef $return_struc)
    $result = StringRegExp($return_struc[3], "([0-9]*)ms", 3)
    If @error Then
        $return_struc[0] = -1
    Else
        $return_struc[0] = $result[0]
    EndIf
EndFunc

Output:

Pinging 100 addresses.
Pinging 74.125.45.1 ... 
Pinging 74.125.45.2 ... 
Pinging 74.125.45.3 ... 
Pinging 74.125.45.4 ... 
Pinging 74.125.45.5 ... 
Pinging 74.125.45.6 ... 
Pinging 74.125.45.7 ... 
Pinging 74.125.45.8 ... 
Pinging 74.125.45.9 ... 
Pinging 74.125.45.10 ... 
74.125.45.6 has a roundtrip of 116.
74.125.45.4 has a roundtrip of 116.
74.125.45.5 has a roundtrip of 116.
Pinging 74.125.45.11 ... 
74.125.45.9 has a roundtrip of 116.
Pinging 74.125.45.12 ... 
Pinging 74.125.45.13 ... 
Pinging 74.125.45.14 ... 
74.125.45.1 is unreachable.
74.125.45.2 is unreachable.
74.125.45.3 is unreachable.
74.125.45.12 is unreachable.
74.125.45.13 is unreachable.
74.125.45.11 is unreachable.
74.125.45.7 is unreachable.
74.125.45.8 is unreachable.
74.125.45.14 is unreachable.
74.125.45.10 is unreachable.
Pinging 74.125.45.15 ... 
Pinging 74.125.45.16 ... 
Pinging 74.125.45.17 ... 
Pinging 74.125.45.18 ... 
Pinging 74.125.45.19 ... 
Pinging 74.125.45.20 ... 
Pinging 74.125.45.21 ... 
Pinging 74.125.45.22 ... 
Pinging 74.125.45.23 ... 
Pinging 74.125.45.24 ... 
74.125.45.16 has a roundtrip of 115.
Pinging 74.125.45.25 ... 
74.125.45.18 has a roundtrip of 114.
74.125.45.17 has a roundtrip of 115.
Pinging 74.125.45.26 ... 
74.125.45.19 has a roundtrip of 115.
Pinging 74.125.45.27 ... 
Pinging 74.125.45.28 ... 
74.125.45.15 is unreachable.
74.125.45.25 is unreachable.
74.125.45.20 is unreachable.
74.125.45.21 is unreachable.
74.125.45.22 is unreachable.
74.125.45.23 is unreachable.
74.125.45.24 is unreachable.
Pinging 74.125.45.29 ... 
Pinging 74.125.45.30 ... 
74.125.45.26 is unreachable.
Pinging 74.125.45.31 ... 
Pinging 74.125.45.32 ... 
Pinging 74.125.45.33 ... 
Pinging 74.125.45.34 ... 
Pinging 74.125.45.35 ... 
Pinging 74.125.45.36 ... 
74.125.45.34 has a roundtrip of 115.
74.125.45.36 has a roundtrip of 115.
74.125.45.32 has a roundtrip of 115.
74.125.45.33 has a roundtrip of 114.
Pinging 74.125.45.37 ... 
74.125.45.35 has a roundtrip of 116.
Pinging 74.125.45.38 ... 
Pinging 74.125.45.39 ... 
Pinging 74.125.45.40 ... 
Pinging 74.125.45.41 ... 
74.125.45.29 is unreachable.
74.125.45.30 is unreachable.
74.125.45.27 is unreachable.
74.125.45.28 is unreachable.
74.125.45.31 is unreachable.
74.125.45.37 is unreachable.
Pinging 74.125.45.42 ... 
Pinging 74.125.45.43 ... 
Pinging 74.125.45.44 ... 
Pinging 74.125.45.45 ... 
Pinging 74.125.45.46 ... 
Pinging 74.125.45.47 ... 
74.125.45.39 has a roundtrip of 115.
74.125.45.38 has a roundtrip of 114.
Pinging 74.125.45.48 ... 
74.125.45.40 has a roundtrip of 115.
74.125.45.41 has a roundtrip of 115.
74.125.45.42 has a roundtrip of 114.
Pinging 74.125.45.49 ... 
Pinging 74.125.45.50 ... 
Pinging 74.125.45.51 ... 
Pinging 74.125.45.52 ... 
74.125.45.43 has a roundtrip of 114.
74.125.45.44 has a roundtrip of 115.
74.125.45.45 has a roundtrip of 115.
74.125.45.47 has a roundtrip of 117.
Pinging 74.125.45.53 ... 
Pinging 74.125.45.54 ... 
Pinging 74.125.45.55 ... 
74.125.45.46 has a roundtrip of 115.
Pinging 74.125.45.56 ... 
Pinging 74.125.45.57 ... 
74.125.45.51 is unreachable.
74.125.45.52 is unreachable.
74.125.45.49 is unreachable.
74.125.45.48 is unreachable.
74.125.45.50 is unreachable.
Pinging 74.125.45.58 ... 
Pinging 74.125.45.59 ... 
Pinging 74.125.45.60 ... 
Pinging 74.125.45.61 ... 
Pinging 74.125.45.62 ... 
74.125.45.53 has a roundtrip of 114.
74.125.45.54 has a roundtrip of 115.
Pinging 74.125.45.63 ... 
Pinging 74.125.45.64 ... 
74.125.45.57 has a roundtrip of 115.
74.125.45.56 has a roundtrip of 115.
Pinging 74.125.45.65 ... 
Pinging 74.125.45.66 ... 
74.125.45.58 has a roundtrip of 114.
74.125.45.59 has a roundtrip of 115.
74.125.45.60 has a roundtrip of 115.
74.125.45.61 has a roundtrip of 114.
74.125.45.62 has a roundtrip of 115.
Pinging 74.125.45.67 ... 
Pinging 74.125.45.68 ... 
74.125.45.63 has a roundtrip of 114.
74.125.45.64 has a roundtrip of 115.
Pinging 74.125.45.69 ... 
Pinging 74.125.45.70 ... 
Pinging 74.125.45.71 ... 
Pinging 74.125.45.72 ... 
Pinging 74.125.45.73 ... 
74.125.45.55 is unreachable.
74.125.45.65 is unreachable.
74.125.45.66 is unreachable.
Pinging 74.125.45.74 ... 
Pinging 74.125.45.75 ... 
Pinging 74.125.45.76 ... 
74.125.45.68 has a roundtrip of 115.
74.125.45.69 has a roundtrip of 116.
Pinging 74.125.45.77 ... 
74.125.45.72 has a roundtrip of 115.
74.125.45.73 has a roundtrip of 115.
Pinging 74.125.45.78 ... 
Pinging 74.125.45.79 ... 
Pinging 74.125.45.80 ... 
74.125.45.74 has a roundtrip of 115.
74.125.45.75 has a roundtrip of 115.
Pinging 74.125.45.81 ... 
Pinging 74.125.45.82 ... 
74.125.45.76 has a roundtrip of 115.
Pinging 74.125.45.83 ... 
74.125.45.77 has a roundtrip of 115.
74.125.45.79 is unreachable.
74.125.45.80 is unreachable.
74.125.45.78 has a roundtrip of 115.
74.125.45.81 is unreachable.
74.125.45.82 is unreachable.
74.125.45.70 is unreachable.
74.125.45.71 is unreachable.
74.125.45.67 is unreachable.
Pinging 74.125.45.84 ... 
Pinging 74.125.45.85 ... 
Pinging 74.125.45.86 ... 
Pinging 74.125.45.87 ... 
Pinging 74.125.45.88 ... 
Pinging 74.125.45.89 ... 
Pinging 74.125.45.90 ... 
Pinging 74.125.45.91 ... 
Pinging 74.125.45.92 ... 
74.125.45.83 has a roundtrip of 115.
Pinging 74.125.45.93 ... 
74.125.45.84 has a roundtrip of 115.
74.125.45.85 has a roundtrip of 116.
74.125.45.86 has a roundtrip of 115.
74.125.45.91 has a roundtrip of 115.
Pinging 74.125.45.94 ... 
Pinging 74.125.45.95 ... 
Pinging 74.125.45.96 ... 
Pinging 74.125.45.97 ... 
74.125.45.93 has a roundtrip of 115.
74.125.45.87 is unreachable.
74.125.45.88 is unreachable.
74.125.45.89 is unreachable.
74.125.45.90 is unreachable.
Pinging 74.125.45.98 ... 
74.125.45.92 is unreachable.
Pinging 74.125.45.99 ... 
Pinging 74.125.45.100 ... 
Ping ready!!

Takes about 4 seconds to ping 100 hosts. It can be faster if you allow more processes to be spawned.

Edited by Manadar
Link to comment
Share on other sites

I am going to write you an alternative, because I am bored and you really deserve an answer after all your efforts.

You would really do that? That's completely incredible. I need to inform you that here at work I have the problem also exists on hosts with Vista and Server 2003...but on my XP machine at home everything works.

Link to comment
Share on other sites

Right above your post. :)

Wow. Something forces you to heave me to the next level in AutoIT programming, right? That code is, ummm, simply great (as fas as I understand it)! I'd never thought it possible to control Microsoft's ping that way...

Link to comment
Share on other sites

Wow. Something forces you to heave me to the next level in AutoIT programming, right? That code is, ummm, simply great (as fas as I understand it)! I'd never thought it possible to control Microsoft's ping that way...

I guess I did feel the need to force you to the next level. Personally, I was more satisfied with the way that the next ping command could start, while the others are still working. But that's just me.

Enjoy this code. Maybe it has changed your mind about this forums support and me.. 8)

Link to comment
Share on other sites

Enjoy this code. Maybe it has changed your mind about this forums support and me.. 8)

I do enjoy, Manadar. Although I still don't understand completely. And: You're actually not the one I criticize: my rant primarily was targeted at November and ProgAndi. You and I had a misunderstanding, nothing more or less...

I've modified your code a little to use it as a function. I've noticed that one has to set $MAX_PROCESS to a value lower than the number of hosts to process. For, e.g., google.com, I set it to 1 (which of course destroys the async mode). When setting a higher value (2 or 3), the results are not displayed. But even if I set it to 1, the result for the last host is missing. Is there a chance to get it?

#include <Constants.au3>
#include <Array.au3>


Local $s_MailRelayFQDN = "google.com"
Local $a_IPs = _LookupIPs($s_MailRelayFQDN)

ConsoleWrite("Pinging " & UBound($a_IPs) & " addresses:" & @CRLF & @CRLF)

$a_IPsChecked = _CheckOnlineStatus($a_IPs, 1)
$a_OnlineIPs = $a_IPsChecked[0]
If IsArray($a_OnlineIPs) Then
    _ArraySort($a_OnlineIPs, "", "", "", 1)
    _ArrayDisplay($a_OnlineIPs)
    ConsoleWrite(@CRLF & "The currently fastest host is: " & $a_OnlineIPs[0][0] & @CRLF)
Else
    ConsoleWrite(@CRLF & "None of the hosts was online!!!" & @CRLF)
EndIf

ConsoleWrite(@CRLF & "Ping ready!!!" & @CRLF)




; Function Name _LookupIPs()
; ==================================================================================================
;
; Function Name:    _CheckOnlineStatus()
; Description:      Checks if hosts are online or not
; Parameter(s):     $a_Hostnames, $i_MaxProcess
; Requirement(s):   AutoIt 3.3
; Return Value(s):  Two arrays containing:
;                   a) the hostnames of the hosts that are online
;                   b) the hostnames of the hosts that are offline
; Author(s):        Manadar
;
; ==================================================================================================
Func _CheckOnlineStatus($a_Hostnames, $i_MaxProcess)

    ; Prepare the asynchronous execution
    Local Const $MAX_PROCESS = $i_MaxProcess ; We spawn a maximum of 8 processes at once
    Local $a_process[$MAX_PROCESS] ; An array to keep a reference to spawned processes, in the next loop we fill it with value 0
    For $i = 0 To UBound($a_process) - 1
        $a_process[$i] = 0
    Next

    Local $a_tmpOnHosts[1][2] ; The array to receive the hosts ONline
    Local $a_tmpOffHosts[1][2] ; The array to receive the hosts OFFline
    
    Local $i = 0 ; A pointer to run through the $a_Hostnames array
    While True

        ; Check on the current processes, and look if there is one finished for use with our next host in line (from $a_Hostnames)
        For $n = 0 To UBound($a_process) - 1
            If ($a_process[$n] == 0) Then ; Check if there is an empty spot
                ; There is an empty spot
                ConsoleWrite("Pinging " & $a_Hostnames[$i] & " ... " & @CRLF)
                $a_process[$n] = _MSPing($a_Hostnames[$i])

                $i += 1
                If ($i == UBound($a_Hostnames)) Then
                    ExitLoop 2
                EndIf
            Else
                ; Something is running here, let's check on the output
                If (_MSPingIsReady($a_process[$n])) Then
                    ; We have an output here, let's get it!
                    $s_hostname = _MSPingGetHostname($a_process[$n])
                    $i_pingtime = _MSPingGetResult($a_process[$n])
                    If ($i_pingtime <> -1) Then
                        ConsoleWrite($s_hostname & " has a roundtrip of " & $i_pingtime & "." & @CRLF)
                        Local $a_TempAdd[2] = [$s_hostname, $i_pingtime]
                        _2DArrayAdd($a_tmpOnHosts, $a_TempAdd, False)
                    Else
                        ConsoleWrite($s_hostname & " is unreachable." & @CRLF)
                        Local $a_TempAdd[2] = [$s_hostname, $i_pingtime]
                        _2DArrayAdd($a_tmpOffHosts, $a_TempAdd, False)
                    EndIf

                    ; Free up an empty space for the next address to Ping
                    $a_process[$n] = 0
                EndIf
            EndIf
        Next
        Sleep(100) ; Give existing ping commands some time to process the request

    WEnd
    
    ; Delete record 0 of the temporary arrays
    _ArrayDelete($a_tmpOnHosts, 0)
    _ArrayDelete($a_tmpOffHosts, 0)

    ; Save both the temporary arrays to a transport array...
    Local $a_Hosts[2]
    $a_Hosts[0] = $a_tmpOnHosts
    $a_Hosts[1] = $a_tmpOffHosts
        
    ; ...return the transport array back to main()
    Return $a_Hosts
    
EndFunc   ;==>_CheckOnlineStatus


; Function Name _LookupIPs()
; ==================================================================================================
;
; Function Name:    _LookupIPs()
; Description:      Gets the IPs of a given FQDN
; Parameter(s):     $s_FQDN
; Requirement(s):   AutoIt 3.2.10.0
; Return Value(s):  An array containing the IP(s) resolved for the given FQDN
; Author(s):        cs/IT solutions
;
; ==================================================================================================
Func _LookupIPs($s_FQDN)

    ; Setup and execute the command and fetch the STDout-data it produces
    $s_STDoutData = _RunReadStd("nslookup " & $s_FQDN, 0, @WorkingDir, 0, 1, @LF)
    ; Put the data to an array
    $a_tmp = StringSplit($s_STDoutData, @CRLF, 2)
    ; Delete the unneeded first 3 records
    For $i = 1 To 3
        _ArrayDelete($a_tmp, 0)
    Next
    ; Add all records to a new string; remove the words "Address" or "Addresses"
    Local $s_tmp
    For $i = 0 To UBound($a_tmp) - 1
        $s_tmp &= StringReplace(StringReplace(StringStripWS($a_tmp[$i], 8), "Address:", ""), "Addresses:", "")
        If $i < UBound($a_tmp) - 1 Then $s_tmp &= ","
    Next
    ; Split the string to an array
    $a_IPs = StringSplit($s_tmp, ",", 2)
    ; Return the array
    Return $a_IPs

EndFunc   ;==>_LookupIPs


; Function Name _RunReadStd()
; ==================================================================================================
;
; Function Name:   _RunReadStd()
; Description::    Run a specified command, and return the Exitcode, StdOut text and
;                  StdErr text from from it. StdOut and StdErr are @tab delimited,
;                  with blank lines removed.
; Parameter(s):    $doscmd: the actual command to run, same as used with Run command
;                  $timeoutSeconds: maximum execution time in seconds, optional, default: 0 (wait forever),
;                  $workingdir: directory in which to execute $doscmd, optional, default: @ScriptDir
;                  $flag: show/hide flag, optional, default: @SW_HIDE
;                  $sDelim: stdOut and stdErr output deliminter, optional, default: @TAB
;                  $nRetVal: return single item from function instead of array, optional, default: -1 (return array)
; Requirement(s):  AutoIt 3.2.10.0
; Return Value(s): An array with three values, Exit Code, StdOut and StdErr
; Author(s):       lod3n
;                  (Thanks to mrRevoked for delimiter choice and non array return selection)
;                  (Thanks to mHZ for _ProcessOpenHandle() and _ProcessGetExitCode())
;                  (MetaThanks to DaveF for posting these DllCalls in Support Forum)
;                  (MetaThanks to JPM for including CloseHandle as needed)
;
; ==================================================================================================
Func _RunReadStd($doscmd, $timeoutSeconds = 0, $workingdir = @ScriptDir, $flag = @SW_HIDE, $nRetVal = -1, $sDelim = @TAB)

    Local $aReturn, $i_Pid, $h_Process, $i_ExitCode, $sStdOut, $sStdErr, $runTimer
    Dim $aReturn[3]

    ; run process with StdErr and StdOut flags
    $runTimer = TimerInit()
    $i_Pid = Run($doscmd, $workingdir, $flag, 6) ; 6 = $STDERR_CHILD+$STDOUT_CHILD

    ; Get process handle
    Sleep(100) ; or DllCall may fail - experimental
    $h_Process = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', 0x400, 'int', 0, 'int', $i_Pid)

    ; create tab delimited string containing StdOut text from process
    $aReturn[1] = ""
    $sStdOut = ""
    While 1
        $sStdOut &= StdoutRead($i_Pid)
        If @error Then ExitLoop
    WEnd
    $sStdOut = StringReplace($sStdOut, @CR, @TAB)
    $sStdOut = StringReplace($sStdOut, @LF, @TAB)
    $aStdOut = StringSplit($sStdOut, @TAB, 1)
    For $i = 1 To $aStdOut[0]
        $aStdOut[$i] = StringStripWS($aStdOut[$i], 3)
        If StringLen($aStdOut[$i]) > 0 Then
            $aReturn[1] &= $aStdOut[$i] & $sDelim
        EndIf
    Next
    $aReturn[1] = StringTrimRight($aReturn[1], 1)

    ; create tab delimited string containing StdErr text from process
    $aReturn[2] = ""
    $sStdErr = ""
    While 1
        $sStdErr &= StderrRead($i_Pid)
        If @error Then ExitLoop
    WEnd
    $sStdErr = StringReplace($sStdErr, @CR, @TAB)
    $sStdErr = StringReplace($sStdErr, @LF, @TAB)
    $aStderr = StringSplit($sStdErr, @TAB, 1)
    For $i = 1 To $aStderr[0]
        $aStderr[$i] = StringStripWS($aStderr[$i], 3)
        If StringLen($aStderr[$i]) > 0 Then
            $aReturn[2] &= $aStderr[$i] & $sDelim
        EndIf
    Next
    $aReturn[2] = StringTrimRight($aReturn[2], 1)

    ; kill the process if it exceeds $timeoutSeconds
    If $timeoutSeconds > 0 Then
        If TimerDiff($runTimer) / 1000 > $timeoutSeconds Then
            ProcessClose($i_Pid)
        EndIf
    EndIf

    ; fetch exit code and close process handle
    If IsArray($h_Process) Then
        Sleep(100) ; or DllCall may fail - experimental
        $i_ExitCode = DllCall('kernel32.dll', 'ptr', 'GetExitCodeProcess', 'ptr', $h_Process[0], 'int*', 0)
        If IsArray($i_ExitCode) Then
            $aReturn[0] = $i_ExitCode[2]
        Else
            $aReturn[0] = -1
        EndIf
        Sleep(100) ; or DllCall may fail - experimental
        DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $h_Process[0])
    Else
        $aReturn[0] = -2
    EndIf

    ; return single item if correctly specified with with $nRetVal
    If $nRetVal <> -1 And $nRetVal >= 0 And $nRetVal <= 2 Then Return $aReturn[$nRetVal]

    ; return array with exit code, stdout, and stderr
    Return $aReturn

EndFunc   ;==>_RunReadStd


; Function Name _MSPing()
; ==================================================================================================
Func _MSPing($hostname, $timeout = 50)
    Local $return_struc[4]
    ; [0] = Result (in ms)
    ; [1] = The hostname originally used
    ; [2] = Process handle (for internal use only)
    ; [3] = Buffer (for internal use only)

    $return_struc[1] = $hostname
    $return_struc[2] = Run("ping " & $hostname & " -n 1 -w " & $timeout, "", @SW_HIDE, $STDOUT_CHILD)

    Return $return_struc
EndFunc   ;==>_MSPing


; Function Name _MSPingIsReady()
; ==================================================================================================
Func _MSPingIsReady(ByRef $return_struc)
    Return ___MSPingReadOutput($return_struc)
EndFunc   ;==>_MSPingIsReady


; Function Name _MSPingGetResult()
; ==================================================================================================
Func _MSPingGetResult($return_struc)
    Return $return_struc[0]
EndFunc   ;==>_MSPingGetResult


; Function Name _MSPingGetHostname()
; ==================================================================================================
Func _MSPingGetHostname($return_struc)
    Return $return_struc[1]
EndFunc   ;==>_MSPingGetHostname


; Function Name ___MSPingReadOutput()
; ==================================================================================================
; Internal use only
Func ___MSPingReadOutput(ByRef $return_struc)
    $data = StdoutRead($return_struc[2])
    If (@error) Then
        ___MSPingParseResult($return_struc)
        Return 1
    Else
        $return_struc[3] &= $data
        Return 0
    EndIf
EndFunc   ;==>___MSPingReadOutput


; Function Name ___MSPingParseResult()
; ==================================================================================================
; Internal use only
Func ___MSPingParseResult(ByRef $return_struc)
    $result = StringRegExp($return_struc[3], "([0-9]*)ms", 3)
    If @error Then
        $return_struc[0] = -1
    Else
        $return_struc[0] = $result[0]
    EndIf
EndFunc   ;==>___MSPingParseResult


; Function __ArrayAdd to add lines to a two-dimensional array
; ==============================================================================================
Func _2DArrayAdd(ByRef $avArray, $vValue, $NestArray = True)
    Local $iBoundArray0, $iBoundArray1, $iBoundArray2, $iBoundValue1
    ; $avArray is not an array
    If IsArray($avArray) = 0 Then Return SetError(1, 0, -1)
    ; No. of dimesions in array
    $iBoundArray0 = UBound($avArray, 0)
    ; $avArray is more than 2D
    If $iBoundArray0 > 2 Then Return SetError(1, 1, -1)
    ; Size of array in first dimension
    $iBoundArray1 = UBound($avArray, 1)
    ; Size of array in second dimension
    If $iBoundArray0 = 2 Then $iBoundArray2 = UBound($avArray, 2)

    ; If input array is 1D, or $vValue is not an array, or $NestArray = True (default) then save $vValue literally
    If ($iBoundArray0 = 1) Or (IsArray($vValue) = 0) Or $NestArray Then
        If $iBoundArray0 = 1 Then
            ; Add to 1D array
            ReDim $avArray[$iBoundArray1 + 1]
            $avArray[$iBoundArray1] = $vValue
        Else
            ; Add to 2D array at [n][0]
            ReDim $avArray[$iBoundArray1 + 1][$iBoundArray2]
            $avArray[$iBoundArray1][0] = $vValue
        EndIf
    Else
        ; If input array is 2D, and $vValue is an array, and $NestArray = False,
        ; then $vValue is a 1D array of values to add as a new row.
        ; $vValue array is not 1D
        If UBound($vValue, 0) <> 1 Then Return SetError(1, 2, -1)
        $iBoundValue1 = UBound($vValue, 1)
        ; $vValue array has too many elements
        If $iBoundArray2 < $iBoundValue1 Then Return SetError(1, 3, -1)
        ReDim $avArray[$iBoundArray1 + 1][$iBoundArray2]
        For $n = 0 To $iBoundValue1 - 1
            $avArray[$iBoundArray1][$n] = $vValue[$n]
        Next
    EndIf

    ; Return index of new last row in $avArray
    Return $iBoundArray1
EndFunc   ;==>__ArrayAdd
Link to comment
Share on other sites

I modified my own example, because I couldn't find the time to try and understand what you had done to mine.

The important part is the ending changed from:

Pinging 74.125.45.94 ... 
Pinging 74.125.45.95 ... 
Pinging 74.125.45.96 ... 
Pinging 74.125.45.97 ... 
74.125.45.93 has a roundtrip of 115.
74.125.45.87 is unreachable.
74.125.45.88 is unreachable.
74.125.45.89 is unreachable.
74.125.45.90 is unreachable.
Pinging 74.125.45.98 ... 
74.125.45.92 is unreachable.
Pinging 74.125.45.99 ... 
Pinging 74.125.45.100 ... 
Ping ready!!

To:

Pinging 74.125.45.95 ... 
Pinging 74.125.45.96 ... 
74.125.45.89 is unreachable.
Pinging 74.125.45.97 ... 
Pinging 74.125.45.98 ... 
74.125.45.91 is unreachable.
Pinging 74.125.45.99 ... 
Pinging 74.125.45.100 ... 
74.125.45.93 has a roundtrip of 115.
74.125.45.96 has a roundtrip of 115.
74.125.45.98 has a roundtrip of 114.
74.125.45.95 has a roundtrip of 115.
74.125.45.97 has a roundtrip of 115.
74.125.45.99 has a roundtrip of 114.
74.125.45.100 has a roundtrip of 114.
74.125.45.92 is unreachable.
74.125.45.94 is unreachable.
Ping ready!!

Code:

#include <Constants.au3>
#include <Array.au3>


#cs
; Simple example:
$a_ping = _MSPing("localhost")
While (Not _MSPingIsReady($a_ping))
    Sleep(250)
WEnd
$pingtime = _MSPingGetResult($a_ping)
MsgBox(0,"", "Ping time: " & $pingtime)
#ce


; Async example

Local Const $MAX_PROCESS = 10 ; We spawn a maximum of 10 processes at once
Local $a_process[$MAX_PROCESS] ; An array to keep a reference to spawned processes, in the next loop we fill it with value 0
For $i = 0 to UBound($a_process)-1
    $a_process[$i] = 0
Next

; The following array represents a list of hosts, these are probably provided from a file later on
Local $address[100]
For $i = 0 to 99
    $address[$i] = "74.125.45." & $i+1 ; We generate some IPs
Next

ConsoleWrite("Pinging " & UBound($address) & " addresses." & @CRLF)

Local $i = 0 ; A pointer to run through the $address array
Local $finished = 0 ; <==== New line
While True
    
    ; Check on the current processes, and look if there is one finished for use with our next host in line (from $address)
    For $n = 0 to UBound($a_process)-1
        If ($i <> UBound($address) AND $a_process[$n] == 0) Then ; Check if we need a spot, and there is an existing spot
            ; There is an empty spot
            ConsoleWrite("Pinging " & $address[$i] & " ... " & @CRLF)
            $a_process[$n] = _MSPing($address[$i])
            
            $i += 1
            ; === This is wrong ===
            ;If ($i == UBound($address)) Then
            ;    ExitLoop 2
            ;EndIf
            ; === This was wrong ===
        Else
            ; Something is running here, let's check on the output
            If ($a_process[$n] <> 0 And _MSPingIsReady($a_process[$n])) Then
                ; We have an output here, let's get it!
                $hostname = _MSPingGetHostname($a_process[$n])
                $pingtime = _MSPingGetResult($a_process[$n])
                If ($pingtime <> -1) Then
                    ConsoleWrite($hostname & " has a roundtrip of " & $pingtime & "." & @CRLF)
                Else
                    ConsoleWrite($hostname & " is unreachable." & @CRLF)
                EndIf
                
                ; Free up an empty space for the next address to Ping
                $a_process[$n] = 0
                
                $finished += 1 ; <=== New line
                If ($finished == UBound($address)) Then
                    ExitLoop 2 ; Return
                EndIf
            EndIf
        EndIf
    Next
    
    Sleep(50) ; Give existing ping commands some time to process the request
WEnd

ConsoleWrite("Ping ready!!" & @CRLF)

Func _MSPing($hostname, $timeout = 50)
    Local $return_struc[4]
    ; [0] = Result (in ms)
    ; [1] = The hostname originally used
    ; [2] = Process handle (for internal use only)
    ; [3] = Buffer (for internal use only)
    
    $return_struc[1] = $hostname
    $return_struc[2] = Run("ping " & $hostname & " -n 1 -w " & $timeout, "", @SW_HIDE, $STDOUT_CHILD)
    
    Return $return_struc
EndFunc

Func _MSPingIsReady(ByRef $return_struc)
    Return ___MSPingReadOutput($return_struc)
EndFunc

Func _MSPingGetResult($return_struc)
    Return $return_struc[0]
EndFunc

Func _MSPingGetHostname($return_struc)
    Return $return_struc[1]
EndFunc

; Internal use only
Func ___MSPingReadOutput(ByRef $return_struc)
    $data = StdoutRead($return_struc[2])
    If (@error) Then
        ___MSPingParseResult($return_struc)
        Return 1
    Else
        $return_struc[3] &= $data
        Return 0
    EndIf
EndFunc

; Internal use only
Func ___MSPingParseResult(ByRef $return_struc)
    $result = StringRegExp($return_struc[3], "([0-9]*)ms", 3)
    If @error Then
        $return_struc[0] = -1
    Else
        $return_struc[0] = $result[0]
    EndIf
EndFunc
Link to comment
Share on other sites

I modified my own example, because I couldn't find the time to try and understand what you had done to mine.

Your changes are perfect, everything works as supposed by now. BTW: I've done nothing hard to understand. I wrapped your code into a function, added the "return-two-arrays"-stuff, where I use 2D-arrays to have records of IP and pingtime and put everything together. Outside the function I sort the array of online hosts after the column containing the pingtimes, so the host in record[0][0] has to be the one reachable fastest. Here the complete code again:

#AutoIt3Wrapper_Change2CUI=y

#include <Constants.au3>
#include <Array.au3>

Local $s_MailRelayFQDN = "google.com"
Local $a_IPs = _LookupIPs($s_MailRelayFQDN)

ConsoleWrite("Pinging " & UBound($a_IPs) & " addresses:" & @CRLF & @CRLF)

$a_IPsChecked = _CheckOnlineStatus($a_IPs, 4)
$a_OnlineIPs = $a_IPsChecked[0]
If IsArray($a_OnlineIPs) Then
    _ArraySort($a_OnlineIPs, "", "", "", 1)
    _ArrayDisplay($a_OnlineIPs)
    ConsoleWrite(@CRLF & "The currently fastest host is: " & $a_OnlineIPs[0][0] & @CRLF)
Else
    ConsoleWrite(@CRLF & "None of the hosts was online!!!" & @CRLF)
EndIf

ConsoleWrite(@CRLF & "Ping ready!!!" & @CRLF)




; Function Name _LookupIPs()
; ==================================================================================================
;
; Function Name:    _CheckOnlineStatus()
; Description:      Checks if hosts are online or not
; Parameter(s):     $a_Hostnames, $i_MaxProcess
; Requirement(s):   AutoIt 3.3
; Return Value(s):  Two arrays containing:
;                   a) the hostnames of the hosts that are online
;                   b) the hostnames of the hosts that are offline
; Author(s):        Manadar
;
; ==================================================================================================
Func _CheckOnlineStatus($a_Hostnames, $i_MaxProcess)

    ; Prepare the asynchronous execution
    Local Const $MAX_PROCESS = $i_MaxProcess ; We spawn a maximum of 8 processes at once
    Local $a_process[$MAX_PROCESS] ; An array to keep a reference to spawned processes, in the next loop we fill it with value 0
    For $i = 0 To UBound($a_process) - 1
        $a_process[$i] = 0
    Next

    Local $a_tmpOnHosts[1][2] ; The array to receive the hosts ONline
    Local $a_tmpOffHosts[1][2] ; The array to receive the hosts OFFline

    Local $i = 0 ; A pointer to run through the $a_Hostnames array
    Local $i_finished = 0
    While True

        ; Check on the current processes, and look if there is one finished for use with our next host in line (from $a_Hostnames)
        For $n = 0 To UBound($a_process) - 1
            If ($i <> UBound($a_Hostnames) And $a_process[$n] == 0) Then ; Check if we need a spot, and there is an existing spot
                ; There is an empty spot
                ConsoleWrite("Pinging " & $a_Hostnames[$i] & " ... " & @CRLF)
                $a_process[$n] = _MSPing($a_Hostnames[$i])
                $i += 1
            Else
                ; Something is running here, let's check on the output
                If ($a_process[$n] <> 0 And _MSPingIsReady($a_process[$n])) Then
                    ; We have an output here, let's get it!
                    $s_hostname = _MSPingGetHostname($a_process[$n])
                    $i_pingtime = _MSPingGetResult($a_process[$n])
                    If ($i_pingtime <> -1) Then
                        ; Do some command line output and add hostnamen / pingtime to a 2D-array
                        ConsoleWrite($s_hostname & " has a roundtrip of " & $i_pingtime & "." & @CRLF)
                        Local $a_TempAdd[2] = [$s_hostname, $i_pingtime]
                        _2DArrayAdd($a_tmpOnHosts, $a_TempAdd, False)
                    Else
                        ; Do some command line output and add hostnamen / pingtime to a 2D-array
                        ConsoleWrite($s_hostname & " is unreachable." & @CRLF)
                        Local $a_TempAdd[2] = [$s_hostname, $i_pingtime]
                        _2DArrayAdd($a_tmpOffHosts, $a_TempAdd, False)
                    EndIf

                    ; Free up an empty space for the next address to ping
                    $a_process[$n] = 0
                    $i_finished += 1
                    If ($i_finished == UBound($a_Hostnames)) Then
                        ExitLoop 2 ; Return
                    EndIf
                EndIf
            EndIf
        Next
        Sleep(50) ; Give existing ping commands some time to process the request

    WEnd

    ; Delete record 0 of the temporary arrays, we don't need the count
    _ArrayDelete($a_tmpOnHosts, 0)
    _ArrayDelete($a_tmpOffHosts, 0)

    ; Save both the temporary arrays to a transport array...
    Local $a_Hosts[2]
    $a_Hosts[0] = $a_tmpOnHosts
    $a_Hosts[1] = $a_tmpOffHosts

    ; ...return the transport array back to main()
    Return $a_Hosts

EndFunc   ;==>_CheckOnlineStatus


; Function Name _LookupIPs()
; ==================================================================================================
;
; Function Name:    _LookupIPs()
; Description:      Gets the IPs of a given FQDN
; Parameter(s):     $s_FQDN
; Requirement(s):   AutoIt 3.2.10.0
; Return Value(s):  An array containing the IP(s) resolved for the given FQDN
; Author(s):        cs/IT solutions
;
; ==================================================================================================
Func _LookupIPs($s_FQDN)

    ; Setup and execute the command and fetch the STDout-data it produces
    $s_STDoutData = _RunReadStd("nslookup " & $s_FQDN, 0, @WorkingDir, 0, 1, @LF)
    ; Put the data to an array
    $a_tmp = StringSplit($s_STDoutData, @CRLF, 2)
    ; Delete the unneeded first 3 records
    For $i = 1 To 3
        _ArrayDelete($a_tmp, 0)
    Next
    ; Add all records to a new string; remove the words "Address" or "Addresses"
    Local $s_tmp
    For $i = 0 To UBound($a_tmp) - 1
        $s_tmp &= StringReplace(StringReplace(StringStripWS($a_tmp[$i], 8), "Address:", ""), "Addresses:", "")
        If $i < UBound($a_tmp) - 1 Then $s_tmp &= ","
    Next
    ; Split the string to an array
    $a_IPs = StringSplit($s_tmp, ",", 2)
    ; Return the array
    Return $a_IPs

EndFunc   ;==>_LookupIPs


; Function Name _RunReadStd()
; ==================================================================================================
;
; Function Name:   _RunReadStd()
; Description::    Run a specified command, and return the Exitcode, StdOut text and
;                  StdErr text from from it. StdOut and StdErr are @tab delimited,
;                  with blank lines removed.
; Parameter(s):    $doscmd: the actual command to run, same as used with Run command
;                  $timeoutSeconds: maximum execution time in seconds, optional, default: 0 (wait forever),
;                  $workingdir: directory in which to execute $doscmd, optional, default: @ScriptDir
;                  $flag: show/hide flag, optional, default: @SW_HIDE
;                  $sDelim: stdOut and stdErr output deliminter, optional, default: @TAB
;                  $nRetVal: return single item from function instead of array, optional, default: -1 (return array)
; Requirement(s):  AutoIt 3.2.10.0
; Return Value(s): An array with three values, Exit Code, StdOut and StdErr
; Author(s):       lod3n
;                  (Thanks to mrRevoked for delimiter choice and non array return selection)
;                  (Thanks to mHZ for _ProcessOpenHandle() and _ProcessGetExitCode())
;                  (MetaThanks to DaveF for posting these DllCalls in Support Forum)
;                  (MetaThanks to JPM for including CloseHandle as needed)
;
; ==================================================================================================
Func _RunReadStd($doscmd, $timeoutSeconds = 0, $workingdir = @ScriptDir, $flag = @SW_HIDE, $nRetVal = -1, $sDelim = @TAB)

    Local $aReturn, $i_Pid, $h_Process, $i_ExitCode, $sStdOut, $sStdErr, $runTimer
    Dim $aReturn[3]

    ; run process with StdErr and StdOut flags
    $runTimer = TimerInit()
    $i_Pid = Run($doscmd, $workingdir, $flag, 6) ; 6 = $STDERR_CHILD+$STDOUT_CHILD

    ; Get process handle
    Sleep(100) ; or DllCall may fail - experimental
    $h_Process = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', 0x400, 'int', 0, 'int', $i_Pid)

    ; create tab delimited string containing StdOut text from process
    $aReturn[1] = ""
    $sStdOut = ""
    While 1
        $sStdOut &= StdoutRead($i_Pid)
        If @error Then ExitLoop
    WEnd
    $sStdOut = StringReplace($sStdOut, @CR, @TAB)
    $sStdOut = StringReplace($sStdOut, @LF, @TAB)
    $aStdOut = StringSplit($sStdOut, @TAB, 1)
    For $i = 1 To $aStdOut[0]
        $aStdOut[$i] = StringStripWS($aStdOut[$i], 3)
        If StringLen($aStdOut[$i]) > 0 Then
            $aReturn[1] &= $aStdOut[$i] & $sDelim
        EndIf
    Next
    $aReturn[1] = StringTrimRight($aReturn[1], 1)

    ; create tab delimited string containing StdErr text from process
    $aReturn[2] = ""
    $sStdErr = ""
    While 1
        $sStdErr &= StderrRead($i_Pid)
        If @error Then ExitLoop
    WEnd
    $sStdErr = StringReplace($sStdErr, @CR, @TAB)
    $sStdErr = StringReplace($sStdErr, @LF, @TAB)
    $aStderr = StringSplit($sStdErr, @TAB, 1)
    For $i = 1 To $aStderr[0]
        $aStderr[$i] = StringStripWS($aStderr[$i], 3)
        If StringLen($aStderr[$i]) > 0 Then
            $aReturn[2] &= $aStderr[$i] & $sDelim
        EndIf
    Next
    $aReturn[2] = StringTrimRight($aReturn[2], 1)

    ; kill the process if it exceeds $timeoutSeconds
    If $timeoutSeconds > 0 Then
        If TimerDiff($runTimer) / 1000 > $timeoutSeconds Then
            ProcessClose($i_Pid)
        EndIf
    EndIf

    ; fetch exit code and close process handle
    If IsArray($h_Process) Then
        Sleep(100) ; or DllCall may fail - experimental
        $i_ExitCode = DllCall('kernel32.dll', 'ptr', 'GetExitCodeProcess', 'ptr', $h_Process[0], 'int*', 0)
        If IsArray($i_ExitCode) Then
            $aReturn[0] = $i_ExitCode[2]
        Else
            $aReturn[0] = -1
        EndIf
        Sleep(100) ; or DllCall may fail - experimental
        DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $h_Process[0])
    Else
        $aReturn[0] = -2
    EndIf

    ; return single item if correctly specified with with $nRetVal
    If $nRetVal <> -1 And $nRetVal >= 0 And $nRetVal <= 2 Then Return $aReturn[$nRetVal]

    ; return array with exit code, stdout, and stderr
    Return $aReturn

EndFunc   ;==>_RunReadStd


; Function Name _MSPing()
; ==================================================================================================
Func _MSPing($hostname, $timeout = 50)
    Local $return_struc[4]
    ; [0] = Result (in ms)
    ; [1] = The hostname originally used
    ; [2] = Process handle (for internal use only)
    ; [3] = Buffer (for internal use only)

    $return_struc[1] = $hostname
    $return_struc[2] = Run("ping " & $hostname & " -n 1 -w " & $timeout, "", @SW_HIDE, $STDOUT_CHILD)

    Return $return_struc
EndFunc   ;==>_MSPing


; Function Name _MSPingIsReady()
; ==================================================================================================
Func _MSPingIsReady(ByRef $return_struc)
    Return ___MSPingReadOutput($return_struc)
EndFunc   ;==>_MSPingIsReady


; Function Name _MSPingGetResult()
; ==================================================================================================
Func _MSPingGetResult($return_struc)
    Return $return_struc[0]
EndFunc   ;==>_MSPingGetResult


; Function Name _MSPingGetHostname()
; ==================================================================================================
Func _MSPingGetHostname($return_struc)
    Return $return_struc[1]
EndFunc   ;==>_MSPingGetHostname


; Function Name ___MSPingReadOutput()
; ==================================================================================================
; Internal use only
Func ___MSPingReadOutput(ByRef $return_struc)
    $data = StdoutRead($return_struc[2])
    If (@error) Then
        ___MSPingParseResult($return_struc)
        Return 1
    Else
        $return_struc[3] &= $data
        Return 0
    EndIf
EndFunc   ;==>___MSPingReadOutput


; Function Name ___MSPingParseResult()
; ==================================================================================================
; Internal use only
Func ___MSPingParseResult(ByRef $return_struc)
    $result = StringRegExp($return_struc[3], "([0-9]*)ms", 3)
    If @error Then
        $return_struc[0] = -1
    Else
        $return_struc[0] = $result[0]
    EndIf
EndFunc   ;==>___MSPingParseResult


; Function __ArrayAdd to add lines to a two-dimensional array
; ==============================================================================================
Func _2DArrayAdd(ByRef $avArray, $vValue, $NestArray = True)
    Local $iBoundArray0, $iBoundArray1, $iBoundArray2, $iBoundValue1
    ; $avArray is not an array
    If IsArray($avArray) = 0 Then Return SetError(1, 0, -1)
    ; No. of dimesions in array
    $iBoundArray0 = UBound($avArray, 0)
    ; $avArray is more than 2D
    If $iBoundArray0 > 2 Then Return SetError(1, 1, -1)
    ; Size of array in first dimension
    $iBoundArray1 = UBound($avArray, 1)
    ; Size of array in second dimension
    If $iBoundArray0 = 2 Then $iBoundArray2 = UBound($avArray, 2)

    ; If input array is 1D, or $vValue is not an array, or $NestArray = True (default) then save $vValue literally
    If ($iBoundArray0 = 1) Or (IsArray($vValue) = 0) Or $NestArray Then
        If $iBoundArray0 = 1 Then
            ; Add to 1D array
            ReDim $avArray[$iBoundArray1 + 1]
            $avArray[$iBoundArray1] = $vValue
        Else
            ; Add to 2D array at [n][0]
            ReDim $avArray[$iBoundArray1 + 1][$iBoundArray2]
            $avArray[$iBoundArray1][0] = $vValue
        EndIf
    Else
        ; If input array is 2D, and $vValue is an array, and $NestArray = False,
        ; then $vValue is a 1D array of values to add as a new row.
        ; $vValue array is not 1D
        If UBound($vValue, 0) <> 1 Then Return SetError(1, 2, -1)
        $iBoundValue1 = UBound($vValue, 1)
        ; $vValue array has too many elements
        If $iBoundArray2 < $iBoundValue1 Then Return SetError(1, 3, -1)
        ReDim $avArray[$iBoundArray1 + 1][$iBoundArray2]
        For $n = 0 To $iBoundValue1 - 1
            $avArray[$iBoundArray1][$n] = $vValue[$n]
        Next
    EndIf

    ; Return index of new last row in $avArray
    Return $iBoundArray1
EndFunc   ;==>_2DArrayAdd

So finally I have to say that you, after destroying my holy weekend :), made two of my days this week. Thank you very much, you're great, dude!!!

Edited by cherdeg
Link to comment
Share on other sites

  • 3 weeks later...

Awesome script Manadar!! I have a use for something like this for a client whose free IP addresses are few and hard to find, so I put a simple GUI on it:

#include <Constants.au3>
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <ProgressConstants.au3>
#include <StaticConstants.au3>

$localip=@IPAddress1
$oct=StringSplit($localip,".")
$range=$oct[1]&"."&$oct[2]&"."&$oct[3]&"."

GUICreate("IP Scanner",300,325,@desktopwidth/2,@desktopheight/4)
GUICtrlCreateLabel("Used IP Addresses",15,5,140,20)
GUICtrlCreateLabel("Free IP Addresses",165,5,140,20)
$used=GUICtrlCreateList("",5,25,140,270)
$open=GUICtrlCreateList("",155,25,140,270)
$prog=GUICtrlCreateProgress(5,300,290,20)
GUISetState(@SW_SHOW,"IP Scanner")

Local $done
Local Const $MAX_PROCESS = 10 ; We spawn a maximum of 10 processes at once
Local $a_process[$MAX_PROCESS] ; An array to keep a reference to spawned processes, in the next loop we fill it with value 0
For $i = 0 to UBound($a_process)-1
    $a_process[$i] = 0
Next

; The following array represents a list of hosts, these are probably provided from a file later on
Local $address[255]
For $i = 0 to 254
    $address[$i] = $range & $i+1 ; We generate some IPs
Next

Local $i = 0 ; A pointer to run through the $address array
Local $finished = 0 ; <==== New line
While True
    
    ; Check on the current processes, and look if there is one finished for use with our next host in line (from $address)
    For $n = 0 to UBound($a_process)-1
        $msg=GUIGetMsg()
        if $msg=$GUI_EVENT_CLOSE then Exit
        If ($i <> UBound($address) AND $a_process[$n] == 0) Then ; Check if we need a spot, and there is an existing spot
            ; There is an empty spot
            $a_process[$n] = _MSPing($address[$i])
            $i += 1
        Else
            ; Something is running here, let's check on the output
            If ($a_process[$n] <> 0 And _MSPingIsReady($a_process[$n])) Then
                ; We have an output here, let's get it!
                
                GUICtrlSetData($prog,($done/255)*100)
                
                $hostname = _MSPingGetHostname($a_process[$n])
                $pingtime = _MSPingGetResult($a_process[$n])
                If ($pingtime <> -1) Then
                    GUICtrlSetData($used,$hostname)
                    $done+=1
                Else
                    GUICtrlSetData($open,$hostname)
                    $done+=1
                EndIf

                ; Free up an empty space for the next address to Ping
                $a_process[$n] = 0
                
                $finished += 1 ; <=== New line
                If ($finished == UBound($address)) Then
                    ExitLoop 2 ; Return
                EndIf
            EndIf
        EndIf
    Next
    
    Sleep(50) ; Give existing ping commands some time to process the request
WEnd

GUICtrlDelete($prog)
GUICtrlCreateLabel("Done scanning IP range",5,300,290,20,$SS_CENTER)

Do
    $msg=GUIGetMsg()
    if $msg=$GUI_EVENT_CLOSE then Exit
Until 1=2



Func _MSPing($hostname, $timeout = 50)
    Local $return_struc[4]
    ; [0] = Result (in ms)
    ; [1] = The hostname originally used
    ; [2] = Process handle (for internal use only)
    ; [3] = Buffer (for internal use only)
    
    $return_struc[1] = $hostname
    $return_struc[2] = Run("ping " & $hostname & " -n 1 -w " & $timeout, "", @SW_HIDE, $STDOUT_CHILD)
    
    Return $return_struc
EndFunc

Func _MSPingIsReady(ByRef $return_struc)
    Return ___MSPingReadOutput($return_struc)
EndFunc

Func _MSPingGetResult($return_struc)
    Return $return_struc[0]
EndFunc

Func _MSPingGetHostname($return_struc)
    Return $return_struc[1]
EndFunc

; Internal use only
Func ___MSPingReadOutput(ByRef $return_struc)
    $data = StdoutRead($return_struc[2])
    If (@error) Then
        ___MSPingParseResult($return_struc)
        Return 1
    Else
        $return_struc[3] &= $data
        Return 0
    EndIf
EndFunc

; Internal use only
Func ___MSPingParseResult(ByRef $return_struc)
    $result = StringRegExp($return_struc[3], "([0-9]*)ms", 3)
    If @error Then
        $return_struc[0] = -1
    Else
        $return_struc[0] = $result[0]
    EndIf
EndFunc

Hopefully this will make a nice addition to a great tool!!

Ian

My projects:

  • IP Scanner - Multi-threaded ping tool to scan your available networks for used and available IP addresses, shows ping times, resolves IPs in to host names, and allows individual IPs to be pinged.
  • INFSniff - Great technicians tool - a tool which scans DriverPacks archives for INF files and parses out the HWIDs to a database file, and rapidly scans the local machine's HWIDs, searches the database for matches, and installs them.
  • PPK3 (Persistent Process Killer V3) - Another for the techs - suppress running processes that you need to keep away, helpful when fighting spyware/viruses.
  • Sync Tool - Folder sync tool with lots of real time information and several checking methods.
  • USMT Front End - Front End for Microsoft's User State Migration Tool, including all files needed for USMT 3.01 and 4.01, 32 bit and 64 bit versions.
  • Audit Tool - Computer audit tool to gather vital hardware, Windows, and Office information for IT managers and field techs. Capabilities include creating a customized site agent.
  • CSV Viewer - Displays CSV files with automatic column sizing and font selection. Lines can also be copied to the clipboard for data extraction.
  • MyDirStat - Lists number and size of files on a drive or specified path, allows for deletion within the app.
  • 2048 Game - My version of 2048, fun tile game.
  • Juice Lab - Ecigarette liquid making calculator.
  • Data Protector - Secure notes to save sensitive information.
  • VHD Footer - Add a footer to a forensic hard drive image to allow it to be mounted or used as a virtual machine hard drive.
  • Find in File - Searches files containing a specified phrase.
Link to comment
Share on other sites

  • 4 weeks later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...