Pinging servers in Python

683,290

Solution 1

This function works in any OS (Unix, Linux, macOS, and Windows)
Python 2 and Python 3

EDITS:
By @radato os.system was replaced by subprocess.call. This avoids shell injection vulnerability in cases where your hostname string might not be validated.

import platform    # For getting the operating system name
import subprocess  # For executing a shell command

def ping(host):
    """
    Returns True if host (str) responds to a ping request.
    Remember that a host may not respond to a ping (ICMP) request even if the host name is valid.
    """

    # Option for the number of packets as a function of
    param = '-n' if platform.system().lower()=='windows' else '-c'

    # Building the command. Ex: "ping -c 1 google.com"
    command = ['ping', param, '1', host]

    return subprocess.call(command) == 0

Note that, according to @ikrase on Windows this function will still return True if you get a Destination Host Unreachable error.

Explanation

The command is ping in both Windows and Unix-like systems.
The option -n (Windows) or -c (Unix) controls the number of packets which in this example was set to 1.

platform.system() returns the platform name. Ex. 'Darwin' on macOS.
subprocess.call() performs a system call. Ex. subprocess.call(['ls','-l']).

Solution 2

If you don't need to support Windows, here's a really concise way to do it:

import os
hostname = "google.com" #example
response = os.system("ping -c 1 " + hostname)

#and then check the response...
if response == 0:
  print hostname, 'is up!'
else:
  print hostname, 'is down!'

This works because ping returns a non-zero value if the connection fails. (The return value actually differs depending on the network error.) You could also change the ping timeout (in seconds) using the '-t' option. Note, this will output text to the console.

Solution 3

There is a module called pyping that can do this. It can be installed with pip

pip install pyping

It is pretty simple to use, however, when using this module, you need root access due to the fact that it is crafting raw packets under the hood.

import pyping

r = pyping.ping('google.com')

if r.ret_code == 0:
    print("Success")
else:
    print("Failed with {}".format(r.ret_code))

Solution 4

import subprocess
ping_response = subprocess.Popen(["/bin/ping", "-c1", "-w100", "192.168.0.1"], stdout=subprocess.PIPE).stdout.read()

Solution 5

For python3 there's a very simple and convenient python module ping3: (pip install ping3, needs root privileges).

from ping3 import ping, verbose_ping
ping('example.com')  # Returns delay in seconds.
>>> 0.215697261510079666

This module allows for the customization of some parameters as well.

Share:
683,290

Related videos on Youtube

Kudu
Author by

Kudu

Updated on May 05, 2022

Comments

  • Kudu
    Kudu about 2 years

    In Python, is there a way to ping a server through ICMP and return TRUE if the server responds, or FALSE if there is no response?

  • Kudu
    Kudu almost 14 years
    The only problem with this is that it wouldn't work on Windows.
  • Catskul
    Catskul about 11 years
    It should be mentioned that the reason something like this is necessary is that ICMP requires root, and /bin/ping gets around this by being set SUID.
  • octern
    octern almost 11 years
    Note: May fail if ping is in a different location. Use whereis ping to get the correct path.
  • MGP
    MGP over 10 years
    I ended up with this variant response = os.system("ping -c 1 -w2 " + hostname + " > /dev/null 2>&1")
  • MGP
    MGP about 10 years
    @jeckyll2hide man ping, send just 1 packet with deadline 2 seconds and redirect all output to /dev/null, retrieve just the return value.
  • skrrgwasme
    skrrgwasme over 9 years
    This code may have the answer to the question, but it would be helpful to add some comments or explanation of how your code is solving the problem.
  • eludom
    eludom over 9 years
    @ManuelGutierrez I think you want "-W 2000" (timeout after 2000 milliseconds) and maybe "-t 3" (exit after 3 seconds, no matter what)
  • Victor Lellis
    Victor Lellis about 9 years
    This works on Windows: ping_response = subprocess.Popen(["ping", hostname, "-n", '1'], stdout=subprocess.PIPE).stdout.read()
  • hek2mgl
    hek2mgl almost 9 years
    You missed to quote hostname!
  • Alan Turing
    Alan Turing almost 9 years
    -w and -W take values in seconds not milliseconds. Check man ping to make sure.
  • Pitto
    Pitto over 8 years
    How can I parse the result to check if the response was ok or ko in Windows?
  • xtofl
    xtofl over 8 years
    To create the subprocess arguments, I usually do "ping -c1 -w100 192.168.0.1".split()
  • Mawg says reinstate Monica
    Mawg says reinstate Monica about 8 years
    pyping does not appear to be a standard module. Perhaps you could provide a link?
  • Frerich Raabe
    Frerich Raabe almost 8 years
    Instead of False if platform.system().lower()=="windows" else True you could of course also just use platform.system().lower() != "windows".
  • Thomas
    Thomas over 7 years
    Thanks! However, I need to run this code as root to make it work.
  • ikrase
    ikrase over 7 years
    Note that this will still return true (on Windows) if you get a "destination host unreachable" reply from a different host.
  • Keeely
    Keeely over 7 years
    Doesn't os.name!="nt" also work? Admittedly I've not tried it on all ver/platform combos!
  • Ben Hyde
    Ben Hyde over 7 years
    "Note that ICMP messages can only be sent from processes running as root (in Windows, you must run this script as ‘Administrator’)."
  • emorris
    emorris about 7 years
    You don't need to use True if condition else False for returning True or False based on a condition. Just use e.g. shell_needed = operating_sys == 'Windows' and return success == 0
  • MikeyE
    MikeyE over 6 years
    I like that you can specify the timeout and count of ICMP requests sent. I was able to write a script which discovers all hosts on the local sub-net. It executes in 1 second, instead of 255 seconds using the os.system('ping -c 1 -t 1 hostname') solution. Plus the pyping lib is very easy to use compared to using the TCP/IP sockets library. I wrote my ping program using both, and pyping is far quicker and easier to use, in my opinion, especially if one isn't familiar with using the TCP/IP sockets library.
  • mountainclimber11
    mountainclimber11 over 6 years
    Good answer. No admin rights required for Windows here.
  • Craynic Cai
    Craynic Cai over 6 years
    awesome library, but need root privileges.
  • womblerone
    womblerone about 6 years
    In my case the default gateway returns an 'unreachable' message, but the windows ping command still has a return code of 0. So this approach worked (sorry for the formatting - its 6 lines, including the functiontion declaration): def ping(host): process = subprocess.Popen(["ping", "-n", "1",host], stdout=subprocess.PIPE, stderr=subprocess.PIPE) streamdata = process.communicate()[0] if 'unreachable' in str(streamdata): return 1 return process.returncode
  • alireza
    alireza about 6 years
    not work with py3. ModuleNotFoundError: No module named 'core'
  • beeb
    beeb almost 6 years
    @wellspokenman you would rather return 0 if unreachable is found in the pipe, no?
  • Cucu
    Cucu almost 6 years
    Nice job mate! If anyone wants to see it in action, just use github.com/romana/multi-ping/blob/master/demo.py
  • womblerone
    womblerone almost 6 years
    @beeb yeah I did that too but forgot to update the comment. My current function looks like this: pastebin.com/FEYWsVjK
  • Andre
    Andre over 5 years
    the 'core' error comes from an incompatibility with python3. i tried to fix it for python3 but it constantly keeps sending me errors. the authors and projects github page is down (404 not found). we'll have to port it by ourselves to python3 :-)
  • Markus
    Markus over 5 years
    I'm finding that I will occasionally get a ping success when my modem is off??? That's testing "8.8.8.8" and "google.com" on a Windows 10 OS. Something is not quite right.
  • ePi272314
    ePi272314 over 5 years
    That cannot happen @Markus. Please, test by hand and with a modified version of the code above, and tell us the result. By hand: 1) open cmd 2) ping 8.8.8.8 -n 1 3) echo %ERRORLEVEL%. Code: Modify the last line of the Python code to return system_call(command). With proper connectivity you will get 0 (zero). With your modem off, you must get some error code. Of course, both methods must return the same error code under same conditions.
  • Markus
    Markus over 5 years
    It did happen and I was using the exact code, word for word. I understand and belief your comments, there is no way a command line ping could succeed when there in no connection, hence my thought something wasn't working correctly in the python to command line operation. I'll give the update a try and see how it goes. Thanks.
  • Source Matters
    Source Matters over 5 years
    I'm just curious - why won't this actually work on Windows?
  • yeaske
    yeaske over 5 years
    @SourceMatters The param to specify number of packets is different for windows (-n) and unix (-c).
  • Source Matters
    Source Matters over 5 years
    Ahh ok cool! I ultimately ended up doing the 2nd Answer instead, and parse the output, as I was a victim of the "Destination Host Unreachable" responses as well.
  • beep_check
    beep_check over 5 years
    for python3 try ping3: github.com/kyan001/ping3 pip install ping3
  • Boris Verkhovskiy
    Boris Verkhovskiy over 5 years
    If you get the hostname string from a user, they could easily hack your server by giving you a "url" like 'google.com; rm -rf /*'. Use subprocess.run(["ping", "-c", "1", hostname]).returncode instead.
  • Boris Verkhovskiy
    Boris Verkhovskiy over 5 years
    @Markus see ikrase's comment.
  • ishahak
    ishahak about 5 years
    Am I the only one here to notice that system.call is a typo and should be subprocess.call?
  • ePi272314
    ePi272314 about 5 years
    You are right. Some one edited my original answer. I will fix that. Thanks
  • Guy Avraham
    Guy Avraham about 5 years
    @alireza - I have encountered it as well. Maybe this will help: stackoverflow.com/questions/35330964/…
  • Stevoisiak
    Stevoisiak almost 5 years
    How would we get the ping response time?
  • Stevoisiak
    Stevoisiak almost 5 years
    How would we get the response time as a variable?
  • Stevoisiak
    Stevoisiak almost 5 years
    Pyping's GitHub page no longer exists and the PyPI package has not been updated since 2016.
  • xCovelus
    xCovelus over 4 years
    ping3: res = ping('8.8.8.8') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/env-admin/.local/lib/python3.6/site-packages/ping3.py‌​", line 165, in ping with socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) as sock: File "/usr/lib/python3.6/socket.py", line 144, in init _socket.socket.__init__(self, family, type, proto, fileno) PermissionError: [Errno 1] Operation not permitted
  • Dysmas
    Dysmas over 4 years
    If you want only 0 or 1, as a response : ping_response = subprocess.call(["ping", "-c1", "-w100", "10.0.0.254"], stdout=subprocess.DEVNULL)
  • Dysmas
    Dysmas over 4 years
    The above solution does not work in Windows, even when adapted : subprocess.call(["ping", "-n", "1", "10.0.0.24"]) It always returns 0.
  • joash
    joash about 4 years
    Am either way receiving True both a right and wrong IP
  • Dimitrios Mistriotis
    Dimitrios Mistriotis about 4 years
    As edited requires root privileges, discussion on lifting this here: github.com/kyan001/ping3/issues/10
  • Clock ZHONG
    Clock ZHONG about 4 years
    Oh, need root prvilege not only for install, but also for execution: ping("example.com")
  • Clock ZHONG
    Clock ZHONG about 4 years
    I got thefollowing errors: import pyping Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.6/dist-packages/pyping/__init__.py", line 3, in <module> from core import * ModuleNotFoundError: No module named 'core'
  • MKANET
    MKANET about 4 years
    Yeah this definitely doesn't work. Just returns :"true" either way on Windows
  • MKANET
    MKANET about 4 years
    Thanks @wellspokenman, pretty much nothing here worked for me correctly under Windows until I tried your solution posted on pastebin.com. Thank you. It's also very fast.
  • Jerther
    Jerther over 3 years
    Such strategy is also useful when the server has a firewall that drops real ICMP pings! Also, here's the GitHub page: github.com/zhengxiaowai/tcping
  • Jann Poppinga
    Jann Poppinga over 3 years
    It's worth mentioning that this too requires root privileges.
  • joe_04_04
    joe_04_04 almost 3 years
    How would you make a cross-compatible timeout flag?
  • Ian Colwell
    Ian Colwell almost 3 years
    Here's my solution from Python 3.6, using the newer subprocess.run: command = ["ping", "-c", "1", "-w2", host] return subprocess.run(args=command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0
  • Joshua
    Joshua almost 3 years
    I can confirm that the windows ping command is hokey with its return value. I am pinging a system I have disconnected from the network, another IP is responding that it isn't available, but I am getting 0% loss and an ERRORLEVEL of 0. Here is a paste of the results pastebin.pl/view/2437bb7c
  • Amandeep Chugh
    Amandeep Chugh over 2 years
    This doesn't need sudo for execution. I'm running python 3.8.10
  • NeilG
    NeilG over 2 years
    Not ICMP but great way to test connection when you can't rely on underlying OS calls. And compact.
  • Billy Cao
    Billy Cao over 2 years
    On Windows, ping -w argument takes MILISECONDS.
  • ratijas
    ratijas over 2 years
    Timeout is measured in seconds, not milliseconds, so a default value of 1000 is unlikely to be useful. Please edit to just "1".
  • Jose Francisco Lopez Pimentel
    Jose Francisco Lopez Pimentel over 2 years
    @ratijas Timeout parameter must be passed in milliseconds, in Windows and Linux. I have just looked for the Mac OS command, and it uses seconds; but anyway, I can't test it on a Mac.
  • Olivier B.
    Olivier B. about 2 years
    This doesn't work on OSX. -w does not exist -> -W ; and it returns False when the ping call actually pings.
  • Olivier B.
    Olivier B. about 2 years
    This seem to works great, but ttl is lowercase on OSX on the ping command output, so for it to works, you need return 'TTL=' in result or 'ttl=' in result
  • Sany
    Sany about 2 years
    If this doesn't work well on windows, it would be good to remove it from the title. This is not the super-universal solution.
  • Sany
    Sany about 2 years
    No problem wit Destination Host Unreachable error - see comment above from @ikrase ?
  • ePi272314
    ePi272314 about 2 years
    Hello @Sany. This solution woks on Windows. The problem reported by ikrase could be solved. I can image two ways of doing that. However, I do not have any installation of Windows available to try. Maybe somebody in a future could improve the answer by including that fix.
  • Florent
    Florent almost 2 years
    In a Celery task and Python 3 it returns FileNotFoundError: [Errno 2] No such file or directory: 'ping': 'ping'