Any of us needs to ping at some point in his life. In fact, it doesn’t matter if you are a network engineer or a programmer – anyone in the IT world knows the ping. This simple command allows you to check if a remote device is alive, and it offers some other amenities. Since its task is simple, we expect ping to be simple. However, Python does not support natively a quick way to ping, so doing it can become a real pain. It is time to change: with Python Ping, you can have your python script pinging in seconds.
Python Ping
Installing Python Ping
Python Ping (pythonping
) is a public repository you can find on PyPI. We have released it with the MIT license, so anyone can use it. Since the repository is on PyPI, you can quickly install it with pip
.
pip install pythonping
Done, we are ready to ping! Just read on…
Just Ping!
from pythonping import ping
ping('8.8.8.8')
This code doesn’t need much explanation. With it, we simply ping Google. However, you won’t see anything in your console if you just run this script. This is because our ping is silent by default, and does not print anything to screen. Why? Because it returns the results instead. If we want to see everything on-screen, we can simply use the verbose
flag.
ping('8.8.8.8', verbose=True)
This will print to screen something like this:
Reply from 8.8.8.8, 9 bytes in 8.17ms
Reply from 8.8.8.8, 9 bytes in 7.14ms
Reply from 8.8.8.8, 9 bytes in 8.12ms
Reply from 8.8.8.8, 9 bytes in 8.12ms
Working with the return values
Printing on-screen is not what we want all the time. This is the reason that makes our script silent by default. Instead, we want other parts of our program to work with the results of the ping. For example, if the remote device is not available we might need to run a script or send an email to the administrator. We might want to prepare custom actions if the latency exceeds a threshold, and so on.
Because of that, our Python Ping returns all the details you may possibly need, in a custom object: ResponseList
. This object is an iterable containing other custom objects, instances of Response
. Each Response
represents the response received from a given ICMP request. It contains its payload (the message), and the time it took to receive it.
Since a Response
is an object, you can get its properties from its members.
error_message
contains a string describing the error this response represents. For example, an error could be “Network Unreachable” or “Fragmentation Required”. If you got a successful response, this property isNone
.success
is a bool indicating if the response is successfultime_elapsed
andtime_elapsed_ms
indicate how long it took to receive this response, respectively in seconds and milliseconds.
You can access individual responses by accessing the _responses
property of your ResponseList
object, returned from ping()
. In this case, _responses
is simply a list. However, _responses are not meant to be accessed from outside the ResponseList
, you should work with ResponseList
directly. On top of that, ResponseList adds some intelligence you can access from its own members. The fields are self-explanatory:
rtt_min
andrtt_min_ms
rtt_max
andrtt_max_ms
rtt_avg
andrtt_avg_ms
Clarify with an example
All of this ResponseList
and Response
concept may seem complex at first. Trust me, it isn’t, and we can see that with an example. First, we need to store our results in an object.
from pythonping import ping
response_list = ping('8.8.8.8', size=40, count=10)
With this ping, we sent 10 ICMP packets with a payload of 40 bytes to Google. To see our average RTT, we can print the rtt_avg_ms
from the response_list
object.
print(response_list.rtt_avg_ms)
That, in our case, yields this:
9.28
And this is it! Simple enough, uh?
Advanced Python Ping
All the parameters of “ping”
Ping is awesome, and simply using what we described above can save you a lot of time. However, you may need to ping in a more sophisticated way from time to time. This is why we packed our Python Ping with features while keeping it simple. In fact, the ping() function expect many parameters besides the target host, that you may want to specify. Here they are.
Parameter | Type | Description |
---|---|---|
target | str | The remote device to ping. This is the only mandatory parameter. |
timeout | int | How long before considering a non-received response lost, in seconds. |
count | int | How many ICMP packets to send in sequence. |
size | int | The size of the entire ICMP packet we want to send. You can leave it to 0, the default value, to adapt the size to the payload and not the other way around. |
payload | str or bytes | The payload of the packet. If you provide also the size of the payload, this will be cut or repeated to match the desired size. |
sweep_start | int | To be used together with sweep_end . It ignores the size and sends each subsequent packet by incrementing payload size by one byte, starting from sweep_start size all the way to sweep_end size. Useful when trying to find MTU. |
sweep_end | int | When doing a ping sweep (with sweep_start ), maximum payload size to reach. |
df | bool | Value for the Don’t Fragment flag of the IP header. |
verbose | bool | True if you wish to write output to the screen. |
out | file | Where to direct the output, by default sys.stdout . |
Customizing the ping
According to the details above, we can customize and tune the ping to perfectly meet our needs. Below, some common examples. Many of you may be familiar with them, as you might have used them in the system ping. With Python Ping, you can do the same in Python.
Stress Test
With this example, you can ensure that the link can handle the load effectively. You send many large packets and see what happens.
ping('8.8.8.8', count=10000, size=1500)
Since we did not specify the payload, it will be random.
Custom payload
In developing an advanced application, you may want to use a custom payload. For example, you can implement a responder to verify the time the packet spent on the network, and the time the packet was processed inside the end devices. In such an example, you may need to use a timestamp as payload. We could do something like this.
import time
ping('8.8.8.8', payload=int(round(time.time())).to_bytes(10, 'little'))
# Use this instead for Python prior to 3.8
ping('8.8.8.8', count=1, payload=bytes(time.clock())
Check MTU with Ping Sweep
To verify how big a packet can be, you can do a ping sweep. This way you will identify the size that will make the remote device stop responding. To do that, we need to start from a relatively small size and go up to a large one.
ping('8.8.8.8', sweep_start=100, sweep_end=1550, df=True)
Note that here we absolutely need the df
flag. In fact, if we don’t use it, routers in the path may fragment the packet so we won’t be able to see the actual MTU.
Conclusion (and link to source!)
So now, with Python Ping, pinging in Python is extremely easy. I hope you can find this module helpful and save time, focusing on what you actually need to do. I suggest you to check two key resources:
Now it is time for you to go out and ping the world! And as always, let me know your thoughts in the comments, and let me know how you are going to use pythonping.