Writing ping() in Julia
TL;DR:
A simple cross-platform ping() function which returns true/false in Julia 1.x can be written
function ping(host::String = "8.8.8.8")
try
run(pipeline(`ping -$(Sys.iswindows() ? "n" : "c") 1 $host`, devnull))
return true
catch
return false
end
endBackground
In general, when testing for Internet connection, my go-to is to check that pinging one of Google’s DNS addresses (8.8.8.8) returns an appropriate response. In Python this can be achieved with what is essentially a one-liner:
import platform, subprocess
def ping(host):
try:
subprocess.check_output("ping -{} 1 {}".format('n' if platform.system().lower() == "windows" else 'c', host), shell = True)
return True
except:
return FalseOwing to its relative infancy, Julia 1.x lacks the many publicly available packages and plethora of questions asked over many years that Python enjoys. Consequently, I struggled to find a similarly simple function in Julia – inbuilt or otherwise – so I decided to write my own.
Composition
Prior to composing my own ping() function, I searched for an existing solution to the problem, and only came across a post from the Julia discourse forum in April 2017 which I thought would prove helpful. The (unofficially) accepted answer was given by
julia> match(r"time=(.*)$", split(readstring(`ping -c 1 8.8.8.8`) , "\n", keep=false)[2])[1]Whilst the question regarded the timing of pings, I figured that I could scavenge the core components and use them for my own purpose. The problem with this solution was that the readstring() function had since been deprecated and no longer existed as part of the language. Consequently, my ping() would have to be written from scratch.
v1.0
The first iteration of my code was rather naïve and brutish, but functional. Firstly, I looked for a way of executing shell commands from within Julia and came across the Cmd objects and the run() function. Utilising these, the starting point was hence
function ping()
run(`ping -c 1 8.8.8.8`)
endOS Generality
The most obvious issue with this was that the -c option is Unix-specific, whereas the intent was to produce a cross-platform function; as such, I found Julia’s inbuilt methods of finding the operating system. Furthermore, one might wish to ping a different host whilst having a default upon which to fall back. A step toward abstraction then resulted in the code becoming
function ping(host::String = "8.8.8.8")
opt::String = ""
if Sys.iswindows()
opt = "-n"
else
opt = "-c"
end
run(`ping $opt 1 $host`)
endStreamlining
The next improvement was to attempt to shorten this code, akin to the earlier Python script. Luckily, Julia has a terse conditional evaluation notation in the form of the ternary operator ?: which can be employed to remove the if-else above:
function ping(host::String = "8.8.8.8")
run(`ping -$(Sys.iswindows() ? "n" : "c") 1 $host`)
endBooleanisation
By this point the ping() function was a one-liner which was able to ping a host of choice. However, it was yet unable to distinguish whether the response was a positive one. Fortuitously, Julia throws an errors when a run() command fails, and so by encapsulating the function within a try-catch, it became possible to return boolean values;
function ping(host::String = "8.8.8.8")
try
run(`ping -$(Sys.iswindows() ? "n" : "c") 1 $host`)
return true
catch
return false
end
endSuppression
One might note that running this results in the ping output being printed in stdout. However, I wished only to know whether it was successful without the details of the message transaction – I therefore wanted to suppress the output. The pipeline method allows output forwarding, which in this case was to be the operating system’s null location. On Windows systems this is nul whereas Unix systems it is /dev/null. One could use another ternary operator to choose the appropriate null, however Julia has an inbuilt devnull constant which generalises the null locations. A combination of these hence permits pings to be sent without cluttering the terminal:
function ping(host::String = "8.8.8.8")
try
run(pipeline(`ping -$(Sys.iswindows() ? "n" : "c") 1 $host`, devnull))
return true
catch
return false
end
end
