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.
14 Responses
Hello Alessandro,
Thank you for sharing this project. I intend to use PythonPing in my work but I am an absolute beginner with Python.
I tried to check the MTU but I get the following error:
>>> ping(‘8.8.8.8’, sweep_start=100, sweep_end=1550, df=True)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
File “/home/val/tutorial_env/lib/python3.7/site-packages/pythonping/__init__.py”, line 52, in ping
comm = executor.Communicator(target, provider, timeout, socket_options=options, verbose=verbose, output=out)
File “/home/val/tutorial_env/lib/python3.7/site-packages/pythonping/executor.py”, line 193, in __init__
self.socket = network.Socket(target, ‘icmp’, source=None, options=socket_options)
File “/home/val/tutorial_env/lib/python3.7/site-packages/pythonping/network.py”, line 27, in __init__
self.socket.setsockopt(options)
TypeError: setsockopt() takes exactly 3 arguments (1 given)
I am using Python 3.7.0
Maybe you can help.
Regards,
Valentin
Hello Valentin,
Thank you so much for this comment! It looks like a bug, due to a misconfiguration inside pythonping. I’ve had a quick look into the code and found a likely issue, I’ll publish a patch very soon. For now, I can tell you it is related to the don’t fragment flag, and besides this feature everything works like a charm.
I’ll keep you posted, and thanks again for experimenting with Python Ping 🙂
PythonPing version 1.0.2 is out now! Install it with pip install pythonping –upgrade.
The program won’t generate an execption anymore, but apparently the DF flag is still not being set on Windows. I’ll need to investigate why, as raw socket programming is somewhat nasty. Nonetheless, I’ll be tracking the bug on GitHub here. 🙂
Thanks for your support Alessandro. I hope I will get some spare time during the weekend to test. If it makes any difference, I am using an Arch Linux machine.
Hi Alessandro,
Here it is:
>>> ping(‘8.8.8.8’, sweep_start=100, sweep_end=1550, df=True)
Reply from 8.8.8.8, 9 bytes in 0.18ms
Reply from 8.8.8.8, 9 bytes in 0.1ms
Reply from 8.8.8.8, 9 bytes in 0.1ms
Reply from 8.8.8.8, 9 bytes in 0.09ms
Round Trip Times min/avg/max is 0.09/0.12/0.18 ms
I am not sure that this is the output we are supposed to get from this command though.
Yes, the output is the same for all commands at the moment. I am also considering adding a cisco-like output with exclamation marks and dots.
Hi, Alessandro
Traceback (most recent call last):
File “/plugin.py”, line 9, in <module>
from pythonping import ping
File “/venv/local/lib/python2.7/site-packages/pythonping/__init__.py”, line 2, in <module>
from . import network, executor, payload_provider
File “/venv/local/lib/python2.7/site-packages/pythonping/executor.py”, line 159
print(value, file=self.output)
^
SyntaxError: invalid syntax
Hello bhavik,
Thank for reaching out. I see you are using a Python 2.7 virtual environment (from File “/venv/local/lib/python2.7/”), but Python Ping supports only Python 3.
Try using Python 3.x and let me know! I would also consider switching your entire project to Python 3, as Python 2.7 will be retired in 2020.
Hello Allessandro,
When I try to iterate over the object ResponseList to get at the individual Responses, I get an error message saying that ResponseList is not an iterable object. Could you please provide a code example of how to use the values in the Response objects that make up ResponseList.
Thanks
Hey Mschormann,
Absolutely. Which python version and pythonping version are you using?
Hi Alessandro,
I’m a beginner with Python so bear with me, but can this be used to with the internal IP address of another PC on the same network? I.e. ping(’10.x.x.x’, verbose = True)? I am currently trying to do and getting “Request timed out”.
Thank you,
Hello Bikran50!
Yes! You can use an IP or hostname you want. If you get request timeout, it is probably because you don’t have network connectivity to that PC.
Could you elaborate on how the ‘out’ parameter works? If I want to output to a .csv file would
ping(‘8.8.8.8’,out = ‘file.csv’)
work?
The output is a file stream, if you don’t want the output to be written in the terminal. However, it just writes text, it does not populate a CSV file.
Comments are closed.