How do I ping a website or IP address with Python?
See this pure Python ping by Matthew Dixon Cowles and Jens Diemer. Also, remember that Python requires root to spawn ICMP (i.e. ping) sockets in linux.
import ping, socket
try:
ping.verbose_ping('www.google.com', count=3)
delay = ping.Ping('www.wikipedia.org', timeout=2000).do()
except socket.error, e:
print "Ping Error:", e
The source code itself is easy to read, see the implementations of verbose_ping and of Ping.do for inspiration.
Depending on what you want to achive, you are probably easiest calling the system ping command..
Using the subprocess module is the best way of doing this, although you have to remember the ping command is different on different operating systems!
import subprocess
host = "www.google.com"
ping = subprocess.Popen(
["ping", "-c", "4", host],
stdout = subprocess.PIPE,
stderr = subprocess.PIPE
)
out, error = ping.communicate()
print out
You don't need to worry about shell-escape characters. For example..
host = "google.com; `echo test`
..will not execute the echo command.
Now, to actually get the ping results, you could parse the out variable. Example output:
round-trip min/avg/max/stddev = 248.139/249.474/250.530/0.896 ms
Example regex:
import re
matcher = re.compile("round-trip min/avg/max/stddev = (\d+.\d+)/(\d+.\d+)/(\d+.\d+)/(\d+.\d+)")
print matcher.search(out).groups()
# ('248.139', '249.474', '250.530', '0.896')
Again, remember the output will vary depending on operating system (and even the version of ping). This isn't ideal, but it will work fine in many situations (where you know the machines the script will be running on)
You may find Noah Gift's presentation Creating Agile Commandline Tools With Python. In it he combines subprocess, Queue and threading to develop solution that is capable of pinging hosts concurrently and speeding up the process. Below is a basic version before he adds command line parsing and some other features. The code to this version and others can be found here
#!/usr/bin/env python2.5
from threading import Thread
import subprocess
from Queue import Queue
num_threads = 4
queue = Queue()
ips = ["10.0.1.1", "10.0.1.3", "10.0.1.11", "10.0.1.51"]
#wraps system ping command
def pinger(i, q):
"""Pings subnet"""
while True:
ip = q.get()
print "Thread %s: Pinging %s" % (i, ip)
ret = subprocess.call("ping -c 1 %s" % ip,
shell=True,
stdout=open('/dev/null', 'w'),
stderr=subprocess.STDOUT)
if ret == 0:
print "%s: is alive" % ip
else:
print "%s: did not respond" % ip
q.task_done()
#Spawn thread pool
for i in range(num_threads):
worker = Thread(target=pinger, args=(i, queue))
worker.setDaemon(True)
worker.start()
#Place work in queue
for ip in ips:
queue.put(ip)
#Wait until worker threads are done to exit
queue.join()
He is also author of: Python for Unix and Linux System Administration
http://ecx.images-amazon.com/images/I/515qmR%2B4sjL._SL500_AA240_.jpg
It's hard to say what your question is, but there are some alternatives.
If you mean to literally execute a request using the ICMP ping protocol, you can get an ICMP library and execute the ping request directly. Google "Python ICMP" to find things like this icmplib. You might want to look at scapy, also.
This will be much faster than using os.system("ping " + ip ).
If you mean to generically "ping" a box to see if it's up, you can use the echo protocol on port 7.
For echo, you use the socket library to open the IP address and port 7. You write something on that port, send a carriage return ("\r\n") and then read the reply.
If you mean to "ping" a web site to see if the site is running, you have to use the http protocol on port 80.
For or properly checking a web server, you use urllib2 to open a specific URL. (/index.html is always popular) and read the response.
There are still more potential meaning of "ping" including "traceroute" and "finger".
I did something similar this way, as an inspiration:
import urllib
import threading
import time
def pinger_urllib(host):
"""
helper function timing the retrival of index.html
TODO: should there be a 1MB bogus file?
"""
t1 = time.time()
urllib.urlopen(host + '/index.html').read()
return (time.time() - t1) * 1000.0
def task(m):
"""
the actual task
"""
delay = float(pinger_urllib(m))
print '%-30s %5.0f [ms]' % (m, delay)
# parallelization
tasks = []
URLs = ['google.com', 'wikipedia.org']
for m in URLs:
t = threading.Thread(target=task, args=(m,))
t.start()
tasks.append(t)
# synchronization point
for t in tasks:
t.join()
Here's a short snippet using subprocess. The check_call method either returns 0 for success, or raises an exception. This way, I don't have to parse the output of ping. I'm using shlex to split the command line arguments.
import subprocess
import shlex
command_line = "ping -c 1 www.google.comsldjkflksj"
args = shlex.split(command_line)
try:
subprocess.check_call(args,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
print "Website is there."
except subprocess.CalledProcessError:
print "Couldn't get a ping."
Most simple answer is:
import os
os.system("ping google.com")
I develop a library that I think could help you. It is called icmplib (unrelated to any other code of the same name that can be found on the Internet) and is a pure implementation of the ICMP protocol in Python.
It is completely object oriented and has simple functions such as the classic ping, multiping and traceroute, as well as low level classes and sockets for those who want to develop applications based on the ICMP protocol.
Here are some other highlights:
Can be run without root privileges.
You can customize many parameters such as the payload of ICMP packets and the traffic class (QoS).
Cross-platform: tested on Linux, macOS and Windows.
Fast and requires few CPU / RAM resources unlike calls made with subprocess.
Lightweight and does not rely on any additional dependencies.
To install it (Python 3.6+ required):
pip3 install icmplib
Here is a simple example of the ping function:
host = ping('1.1.1.1', count=4, interval=1, timeout=2, privileged=True)
if host.is_alive:
print(f'{host.address} is alive! avg_rtt={host.avg_rtt} ms')
else:
print(f'{host.address} is dead')
Set the "privileged" parameter to False if you want to use the library without root privileges.
You can find the complete documentation on the project page:
https://github.com/ValentinBELYN/icmplib
Hope you will find this library useful.
read a file name, the file contain the one url per line, like this:
http://www.poolsaboveground.com/apache/hadoop/core/
http://mirrors.sonic.net/apache/hadoop/core/
use command:
python url.py urls.txt
get the result:
Round Trip Time: 253 ms - mirrors.sonic.net
Round Trip Time: 245 ms - www.globalish.com
Round Trip Time: 327 ms - www.poolsaboveground.com
source code(url.py):
import re
import sys
import urlparse
from subprocess import Popen, PIPE
from threading import Thread
class Pinger(object):
def __init__(self, hosts):
for host in hosts:
hostname = urlparse.urlparse(host).hostname
if hostname:
pa = PingAgent(hostname)
pa.start()
else:
continue
class PingAgent(Thread):
def __init__(self, host):
Thread.__init__(self)
self.host = host
def run(self):
p = Popen('ping -n 1 ' + self.host, stdout=PIPE)
m = re.search('Average = (.*)ms', p.stdout.read())
if m: print 'Round Trip Time: %s ms -' % m.group(1), self.host
else: print 'Error: Invalid Response -', self.host
if __name__ == '__main__':
with open(sys.argv[1]) as f:
content = f.readlines()
Pinger(content)
import subprocess as s
ip=raw_input("Enter the IP/Domain name:")
if(s.call(["ping",ip])==0):
print "your IP is alive"
else:
print "Check ur IP"
If you want something actually in Python, that you can play with, have a look at Scapy:
from scapy.all import *
request = IP(dst="www.google.com")/ICMP()
answer = sr1(request)
That's in my opinion much better (and fully cross-platform), than some funky subprocess calls. Also you can have as much information about the answer (sequence ID.....) as you want, as you have the packet itself.
using system ping command to ping a list of hosts:
import re
from subprocess import Popen, PIPE
from threading import Thread
class Pinger(object):
def __init__(self, hosts):
for host in hosts:
pa = PingAgent(host)
pa.start()
class PingAgent(Thread):
def __init__(self, host):
Thread.__init__(self)
self.host = host
def run(self):
p = Popen('ping -n 1 ' + self.host, stdout=PIPE)
m = re.search('Average = (.*)ms', p.stdout.read())
if m: print 'Round Trip Time: %s ms -' % m.group(1), self.host
else: print 'Error: Invalid Response -', self.host
if __name__ == '__main__':
hosts = [
'www.pylot.org',
'www.goldb.org',
'www.google.com',
'www.yahoo.com',
'www.techcrunch.com',
'www.this_one_wont_work.com'
]
Pinger(hosts)
You can find an updated version of the mentioned script that works on both Windows and Linux here
using subprocess ping command to ping decode it because the response is binary:
import subprocess
ping_response = subprocess.Popen(["ping", "-a", "google.com"], stdout=subprocess.PIPE).stdout.read()
result = ping_response.decode('utf-8')
print(result)
you might try socket to get ip of the site and use scrapy to excute icmp ping to the ip.
import gevent
from gevent import monkey
# monkey.patch_all() should be executed before any library that will
# standard library
monkey.patch_all()
import socket
from scapy.all import IP, ICMP, sr1
def ping_site(fqdn):
ip = socket.gethostbyaddr(fqdn)[-1][0]
print(fqdn, ip, '\n')
icmp = IP(dst=ip)/ICMP()
resp = sr1(icmp, timeout=10)
if resp:
return (fqdn, False)
else:
return (fqdn, True)
sites = ['www.google.com', 'www.baidu.com', 'www.bing.com']
jobs = [gevent.spawn(ping_site, fqdn) for fqdn in sites]
gevent.joinall(jobs)
print([job.value for job in jobs])
On python 3 you can use ping3.
from ping3 import ping, verbose_ping
ip-host = '8.8.8.8'
if not ping(ip-host):
raise ValueError('{} is not available.'.format(ip-host))
If you only want to check whether a machine on an IP is active or not, you can just use python sockets.
import socket
s = socket.socket()
try:
s.connect(("192.168.1.123", 1234)) # You can use any port number here
except Exception as e:
print(e.errno, e)
Now, according to the error message displayed (or the error number), you can determine whether the machine is active or not.
Use this it's tested on python 2.7 and works fine it returns ping time in milliseconds if success and return False on fail.
import platform,subproccess,re
def Ping(hostname,timeout):
if platform.system() == "Windows":
command="ping "+hostname+" -n 1 -w "+str(timeout*1000)
else:
command="ping -i "+str(timeout)+" -c 1 " + hostname
proccess = subprocess.Popen(command, stdout=subprocess.PIPE)
matches=re.match('.*time=([0-9]+)ms.*', proccess.stdout.read(),re.DOTALL)
if matches:
return matches.group(1)
else:
return False
I'm having a bit of trouble. I want to create a simple program that connects to the server and executes a command using subprocess then returns the result to the client. It's simple but I can't get it to work. Right now this is what I have:
client:
import sys, socket, subprocess
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = sys.argv[1]
port = int(sys.argv[2])
socksize = 1024
conn.connect((host, port))
while True:
shell = raw_input("$ ")
conn.send(shell)
data = conn.recv(socksize)
#msglen = len(data)
output = data
iotype = subprocess.PIPE
cmd = ['/bin/sh', '-c', shell]
proc = subprocess.Popen(cmd, stdout=iotype).wait()
stdout,stderr = proc.communicate()
conn.send(stdout)
print(output)
if proc.returncode != 0:
print("Error")
server:
import sys, socket, subprocess
host = ''
port = 50106
socksize = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
print("Server started on port: %s" %port)
s.listen(1)
print("Now listening...\n")
conn, addr = s.accept()
while True:
print 'New connection from %s:%d' % (addr[0], addr[1])
data = conn.recv(socksize)
cmd = ['/bin/sh', '-c', data]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE).wait()
stdout,stderr = cmd.communicate()
if not data:
break
elif data == 'killsrv':
sys.exit()
Danger, Will Robinson!!!
Do you really want to send commands in clear text without authentication over the network? It is very, very dangerous.
Do it over SSH with paramiko.
Alright I've heard this answer too many times. I don't want to use SSH I'm just building it to learn more about sockets. I'm not going to actually use this if I want to send commands to a system. – AustinM
There is no way I could infer this noble quest from your question. :-)
The sockets module is a thin layer over the posix library; plain sockets is tedious and hard to get right. As of today (2014), asynchronous I/O and concurrency are not among Python's strongest traits - 3.4 is starting to change that but libraries will lag behind for a while. My advice is to spent your time learning some higher level API like Twisted (twistedmatrix.com/trac). If you are really interested in the low level stuff, dive in the project source.
Alright. Any idea on how I could use twisted for this type of thing? – AustinM
Look at twistedmatrix.com/documents/current/core/examples/#auto2
Well I can understand your frustration Austin; I was in the same boat. However trial and error at last worked out. Hopefully you were looking for this:
print "Command is:",command
op = subprocess.Popen(command, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
if op:
output=str(op.stdout.read())
print "Output:",output
conn.sendall(output)
else:
error=str(op.stderr.read())
print "Error:",error
conn.sendall(error)
It's unclear why you are using subprocess.Popen() for the same command in both the client and the server. Here's an outline of what I would try to do (pseudocode):
client
while True:
read command from user
send command to server
wait for and then read response from server
print response to user
server
while True:
wait for and then read command from client
if command is "killsrv", exit
execute command and capture output
send output to client
The problem with your code is this line (in both client and server):
proc = subprocess.Popen(cmd, stdout=iotype).wait()
stdout,stderr = proc.communicate()
You are calling wait on the Popen object, which means that the variable proc is getting an int (returned by wait) instead of a Popen object. You can just get rid of the wait -- since communicate waits for the process to end before returning, and you aren't checking the exit code anyway, you don't need to call it.
Then, in your client, I don't think you even need the subprocess calls, unless you're running some command that the server is sending back.
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?
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.
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']).
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))
import subprocess
ping_response = subprocess.Popen(["/bin/ping", "-c1", "-w100", "192.168.0.1"], stdout=subprocess.PIPE).stdout.read()
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.
Programmatic ICMP ping is complicated due to the elevated privileges required to send raw ICMP packets, and calling ping binary is ugly. For server monitoring, you can achieve the same result using a technique called TCP ping:
# pip3 install tcping
>>> from tcping import Ping
# Ping(host, port, timeout)
>>> ping = Ping('212.69.63.54', 22, 60)
>>> ping.ping(3)
Connected to 212.69.63.54[:22]: seq=1 time=23.71 ms
Connected to 212.69.63.54[:22]: seq=2 time=24.38 ms
Connected to 212.69.63.54[:22]: seq=3 time=24.00 ms
Internally, this simply establishes a TCP connection to the target server and drops it immediately, measuring time elapsed. This particular implementation is a bit limited in that it doesn't handle closed ports but for your own servers it works pretty well.
Because I like to have my Python program universal on version 2.7 and 3.x and on platform Linux, Mac OS and Windows, I had to modify the existing examples.
# shebang does not work over all platforms
# ping.py 2016-02-25 Rudolf
# subprocess.call() is preferred to os.system()
# works under Python 2.7 and 3.4
# works under Linux, Mac OS, Windows
def ping(host):
"""
Returns True if host responds to a ping request
"""
import subprocess, platform
# Ping parameters as function of OS
ping_str = "-n 1" if platform.system().lower()=="windows" else "-c 1"
args = "ping " + " " + ping_str + " " + host
need_sh = False if platform.system().lower()=="windows" else True
# Ping
return subprocess.call(args, shell=need_sh) == 0
# test call
print(ping("192.168.17.142"))
using socket package in python3:
import socket
def ping_server(server: str, port: int, timeout=3):
"""ping server"""
try:
socket.setdefaulttimeout(timeout)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((server, port))
except OSError as error:
return False
else:
s.close()
return True
My version of a ping function:
Works on Python 3.5 and later, on Windows and Linux.
On Windows, returns False if the ping command fails with "Destination Host Unreachable".
And does not show any output, either as a pop-up window or in command line.
import platform, subprocess
def ping(host_or_ip, packets=1, timeout=1000):
''' Calls system "ping" command, returns True if ping succeeds.
Required parameter: host_or_ip (str, address of host to ping)
Optional parameters: packets (int, number of retries), timeout (int, ms to wait for response)
Does not show any output, either as popup window or in command line.
Python 3.5+, Windows and Linux compatible
'''
# The ping command is the same for Windows and Linux, except for the "number of packets" flag.
if platform.system().lower() == 'windows':
command = ['ping', '-n', str(packets), '-w', str(timeout), host_or_ip]
# run parameters: capture output, discard error messages, do not show window
result = subprocess.run(command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, creationflags=0x08000000)
# 0x0800000 is a windows-only Popen flag to specify that a new process will not create a window.
# On Python 3.7+, you can use a subprocess constant:
# result = subprocess.run(command, capture_output=True, creationflags=subprocess.CREATE_NO_WINDOW)
# On windows 7+, ping returns 0 (ok) when host is not reachable; to be sure host is responding,
# we search the text "TTL=" on the command output. If it's there, the ping really had a response.
return result.returncode == 0 and b'TTL=' in result.stdout
else:
command = ['ping', '-c', str(packets), '-w', str(timeout), host_or_ip]
# run parameters: discard output and error messages
result = subprocess.run(command, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return result.returncode == 0
Feel free to use it as you will.
#!/usr/bin/python3
import subprocess as sp
def ipcheck():
status,result = sp.getstatusoutput("ping -c1 -w2 " + str(pop))
if status == 0:
print("System " + str(pop) + " is UP !")
else:
print("System " + str(pop) + " is DOWN !")
pop = input("Enter the ip address: ")
ipcheck()
After looking around, I ended up writing my own ping module, which is designed to monitor large numbers of addresses, is asynchronous and doesn't use a lot of system resources. You can find it here: https://github.com/romana/multi-ping/ It's Apache licensed, so you can use it in your project in any way you see fit.
The main reasons for implementing my own are the restrictions of the other approaches:
Many of the solutions mentioned here require an exec out to a command line utility. This is quite inefficient and resource hungry if you need to monitor large numbers of IP addresses.
Others mention some older python ping modules. I looked at those and in the end, they all had some issue or the other (such as not correctly setting packet IDs) and didn't handle the ping-ing of large numbers of addresses.
I resolve this with:
def ping(self, host):
res = False
ping_param = "-n 1" if system_name().lower() == "windows" else "-c 1"
resultado = os.popen("ping " + ping_param + " " + host).read()
if "TTL=" in resultado:
res = True
return res
"TTL" is the way to know if the ping is correctly.
Saludos
Make Sure pyping is installed or install it pip install pyping
#!/usr/bin/python
import pyping
response = pyping.ping('Your IP')
if response.ret_code == 0:
print("reachable")
else:
print("unreachable")
If your server does not support ICMP (firewall might block it), it most probably still offers a service on a TCP port. In this case, you can perform a TCP ping1 (platform independently and without installing additional python modules) like this:
import socket
def isReachable(ipOrName, port, timeout=2):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
try:
s.connect((ipOrName, int(port)))
s.shutdown(socket.SHUT_RDWR)
return True
except:
return False
finally:
s.close()
The code is taken and only slightly modified from here.
1 A TCP ping does not really exist as a ping is performed with ICMP on ISO/OSI layer 3. A TCP ping is performed on ISO/OSI layer 4. It just tries to connect to a TCP port in the most basic way, that it is not transmitting any data, but closing the connection immediately after connecting.
#!/usr/bin/python3
import subprocess as sp
ip = "192.168.122.60"
status,result = sp.getstatusoutput("ping -c1 -w2 " + ip)
if status == 0:
print("System " + ip + " is UP !")
else:
print("System " + ip + " is DOWN !")
My reduction using ideas from answers in this post but only using the newer recommended subprocess module and python3:
import subprocess
import platform
operating_sys = platform.system()
nas = '192.168.0.10'
def ping(ip):
# ping_command = ['ping', ip, '-n', '1'] instead of ping_command = ['ping', ip, '-n 1'] for Windows
ping_command = ['ping', ip, '-n', '1'] if operating_sys == 'Windows' else ['ping', ip, '-c 1']
shell_needed = True if operating_sys == 'Windows' else False
ping_output = subprocess.run(ping_command,shell=shell_needed,stdout=subprocess.PIPE)
success = ping_output.returncode
return True if success == 0 else False
out = ping(nas)
print(out)
This script works on Windows, and should work on other OSes :
It works on Windows, Debian, and macosx, need a test on solaris.
import os
import platform
def isUp(hostname):
giveFeedback = False
if platform.system() == "Windows":
response = os.system("ping "+hostname+" -n 1")
else:
response = os.system("ping -c 1 " + hostname)
isUpBool = False
if response == 0:
if giveFeedback:
print hostname, 'is up!'
isUpBool = True
else:
if giveFeedback:
print hostname, 'is down!'
return isUpBool
print(isUp("example.com")) #Example domain
print(isUp("localhost")) #Your computer
print(isUp("invalid.example.com")) #Unresolvable hostname: https://tools.ietf.org/html/rfc6761
print(isUp("192.168.1.1")) #Pings local router
print(isUp("192.168.1.135")) #Pings a local computer - will differ for your network
I ended up finding this question regarding a similar scenario. I tried out pyping but the example given by Naveen didn't work for me in Windows under Python 2.7.
An example that worked for me is:
import pyping
response = pyping.send('Your IP')
if response['ret_code'] == 0:
print("reachable")
else:
print("unreachable")
Using Multi-ping (pip install multiPing) I made this simple code (simply copy and paste if you will!):
from multiping import MultiPing
def ping(host,n = 0):
if(n>0):
avg = 0
for i in range (n):
avg += ping(host)
avg = avg/n
# Create a MultiPing object to test hosts / addresses
mp = MultiPing([host])
# Send the pings to those addresses
mp.send()
# With a 1 second timout, wait for responses (may return sooner if all
# results are received).
responses, no_responses = mp.receive(1)
for addr, rtt in responses.items():
RTT = rtt
if no_responses:
# Sending pings once more, but just to those addresses that have not
# responded, yet.
mp.send()
responses, no_responses = mp.receive(1)
RTT = -1
return RTT
Usage:
#Getting the latency average (in seconds) of host '192.168.0.123' using 10 samples
ping('192.168.0.123',10)
If you want a single sample, the second parameter "10" can be ignored!
Hope it helps!
I needed a faster ping sweep and I didn't want to use any external libraries, so I resolved to using concurrency using built-in asyncio.
This code requires python 3.7+ and is made and tested on Linux only. It won't work on Windows but I am sure you can easily change it to work on Windows.
I ain't an expert with asyncio but I used this great article Speed Up Your Python Program With Concurrency and I came up with these lines of codes. I tried to make it as simple as possible, so most likely you will need to add more code to it to suit your needs.
It doesn't return true or false, I thought it would be more convenient just to make it print the IP that responds to a ping request. I think it is pretty fast, pinging 255 ips in nearly 10 seconds.
#!/usr/bin/python3
import asyncio
async def ping(host):
"""
Prints the hosts that respond to ping request
"""
ping_process = await asyncio.create_subprocess_shell("ping -c 1 " + host + " > /dev/null 2>&1")
await ping_process.wait()
if ping_process.returncode == 0:
print(host)
return
async def ping_all():
tasks = []
for i in range(1,255):
ip = "192.168.1.{}".format(i)
task = asyncio.ensure_future(ping(ip))
tasks.append(task)
await asyncio.gather(*tasks, return_exceptions = True)
asyncio.run(ping_all())
Sample output:
192.168.1.1
192.168.1.3
192.168.1.102
192.168.1.106
192.168.1.6
Note that the IPs are not in order, as the IP is printed as soon it replies, so the one that responds first gets printed first.
on linux, it's possible to create ICMP datagram (not raw) sockets without being root (or setuid or CAP_NET_RAW): https://unix.stackexchange.com/a/592914. I ended up with
$ id
uid=1000(raylu) gid=1000(raylu) [...]
$ sudo sysctl net.ipv4.ping_group_range='1000 1000'
import socket
import struct
import time
def main():
ping('192.168.1.10')
def ping(destination):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.getprotobyname('icmp'))
sock.settimeout(10.0)
start_time = time.time_ns() # python 3.7+ only
payload = struct.pack('L', start_time)
sock.sendto(encode(payload), (destination, 0))
while (time.time_ns() - start_time) // 1_000_000_000 < 10:
try:
data, source = sock.recvfrom(256)
except socket.timeout:
print('timed out')
return
message_type, message_code, check, identifier, sequence_number = struct.unpack('bbHHh', data[:8])
if source == (destination, 0) and message_type == ICMP.ECHO_REPLY and data[8:] == payload:
print((time.time_ns() - start_time) // 1_000_000, 'ms')
break
else:
print('got unexpected packet from %s:' % source[0], message_type, data[8:])
else:
print('timed out')
def encode(payload: bytes):
# calculate checksum with check set to 0
checksum = calc_checksum(icmp_header(ICMP.ECHO_REQUEST, 0, 0, 1, 1) + payload)
# craft the packet again with the checksum set
return icmp_header(ICMP.ECHO_REQUEST, 0, checksum, 1, 1) + payload
def icmp_header(message_type, message_code, check, identifier, sequence_number) -> bytes:
return struct.pack('bbHHh', message_type, message_code, check, identifier, sequence_number)
def calc_checksum(data: bytes) -> int:
'''RFC 1071'''
# code stolen from https://github.com/alessandromaggio/pythonping/blob/a59ce65a/pythonping/icmp.py#L8
'''
MIT License
Copyright (c) 2018 Alessandro Maggio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''
subtotal = 0
for i in range(0, len(data)-1, 2):
subtotal += (data[i] << 8) + data[i+1]
if len(data) % 2:
subtotal += (data[len(data)-1] << 8)
while subtotal >> 16:
subtotal = (subtotal & 0xFFFF) + (subtotal >> 16)
check = ~subtotal
return ((check << 8) & 0xFF00) | ((check >> 8) & 0x00FF)
class ICMP:
ECHO_REPLY = 0
ECHO_REQUEST = 8
though many of the packages other answers have suggested here would work too
Seems simple enough, but gave me fits. I kept getting "icmp open socket operation not permitted" or else the solutions would hang up if the server was off line. If, however, what you want to know is that the server is alive and you are running a web server on that server, then curl will do the job. If you have ssh and certificates, then ssh and a simple command will suffice. Here is the code:
from easyprocess import EasyProcess # as root: pip install EasyProcess
def ping(ip):
ping="ssh %s date;exit"%(ip) # test ssh alive or
ping="curl -IL %s"%(ip) # test if http alive
response=len(EasyProcess(ping).call(timeout=2).stdout)
return response #integer 0 if no response in 2 seconds
Use this it's tested on python 2.7 and works fine it returns ping time in milliseconds if success and return False on fail.
import platform,subproccess,re
def Ping(hostname,timeout):
if platform.system() == "Windows":
command="ping "+hostname+" -n 1 -w "+str(timeout*1000)
else:
command="ping -i "+str(timeout)+" -c 1 " + hostname
proccess = subprocess.Popen(command, stdout=subprocess.PIPE)
matches=re.match('.*time=([0-9]+)ms.*', proccess.stdout.read(),re.DOTALL)
if matches:
return matches.group(1)
else:
return False
I had similar requirement so i implemented it as shown below. It is tested on Windows 64 bit and Linux.
import subprocess
def systemCommand(Command):
Output = ""
Error = ""
try:
Output = subprocess.check_output(Command,stderr = subprocess.STDOUT,shell='True')
except subprocess.CalledProcessError as e:
#Invalid command raises this exception
Error = e.output
if Output:
Stdout = Output.split("\n")
else:
Stdout = []
if Error:
Stderr = Error.split("\n")
else:
Stderr = []
return (Stdout,Stderr)
#in main
Host = "ip to ping"
NoOfPackets = 2
Timeout = 5000 #in milliseconds
#Command for windows
Command = 'ping -n {0} -w {1} {2}'.format(NoOfPackets,Timeout,Host)
#Command for linux
#Command = 'ping -c {0} -w {1} {2}'.format(NoOfPackets,Timeout,Host)
Stdout,Stderr = systemCommand(Command)
if Stdout:
print("Host [{}] is reachable.".format(Host))
else:
print("Host [{}] is unreachable.".format(Host))
When IP is not reachable subprocess.check_output() raises an exception. Extra verification can be done by extracting information from output line 'Packets: Sent = 2, Received = 2, Lost = 0 (0% loss)'.
WINDOWS ONLY - Can't believe no-ones cracked open Win32_PingStatus
Using a simple WMI query we return an object full of really detailed info for free
import wmi
# new WMI object
c = wmi.WMI()
# here is where the ping actually is triggered
x = c.Win32_PingStatus(Address='google.com')
# how big is this thing? - 1 element
print 'length x: ' ,len(x)
#lets look at the object 'WMI Object:\n'
print x
#print out the whole returned object
# only x[0] element has values in it
print '\nPrint Whole Object - can directly reference the field names:\n'
for i in x:
print i
#just a single field in the object - Method 1
print 'Method 1 ( i is actually x[0] ) :'
for i in x:
print 'Response:\t', i.ResponseTime, 'ms'
print 'TTL:\t', i.TimeToLive
#or better yet directly access the field you want
print '\npinged ', x[0].ProtocolAddress, ' and got reply in ', x[0].ResponseTime, 'ms'
sample output
Here's a solution using Python's subprocess module and the ping CLI tool provided by the underlying OS. Tested on Windows and Linux. Support setting a network timeout. Doesn't need root privileges (at least on Windows and Linux).
import platform
import subprocess
def ping(host, network_timeout=3):
"""Send a ping packet to the specified host, using the system "ping" command."""
args = [
'ping'
]
platform_os = platform.system().lower()
if platform_os == 'windows':
args.extend(['-n', '1'])
args.extend(['-w', str(network_timeout * 1000)])
elif platform_os in ('linux', 'darwin'):
args.extend(['-c', '1'])
args.extend(['-W', str(network_timeout)])
else:
raise NotImplemented('Unsupported OS: {}'.format(platform_os))
args.append(host)
try:
if platform_os == 'windows':
output = subprocess.run(args, check=True, universal_newlines=True).stdout
if output and 'TTL' not in output:
return False
else:
subprocess.run(args, check=True)
return True
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
return False
My take borrowing from other answers. Attempt to simplify and minimize queries.
import platform, os
def ping(host):
result = os.popen(' '.join(("ping", ping.param, host))).read()
return 'ttl=' in result.lower()
ping.param = "-n 1" if platform.system().lower() == "windows" else "-c 1"
EDIT: ignoring case in return as per comment by Olivier B.
import os #to get clear screen
import subprocess as sp #to get system ping
os.system("clear") #clear screen
print('Wait or Press Ctrl+Z to Terminate\n') #notice to terminate or wait
for i in range(255): #0 to 255 loop
ip='192.168.1.'+str(i) #concatenating str and int
s,r=sp.getstatusoutput("ping -c1 -w2 " + ip) #ping and store status in s
if s==0: #if status is 0 equal to pass
print(ip+" is UP ✓ ") #output
else: #if status is not 0 equal to fail
pass #skip and try next ip from loop
Ping them all in windows or linux, return a sorted list. This is a hybrid/fix from the responses #Ahmed Essam and #Arno.
import asyncio
import re
import platform
isWindows = platform.system()
async def ping(host):
cmd = 'ping {} {} 1'.format(host, '-n' if isWindows else '-c')
ping_proc = \
await asyncio.create_subprocess_shell(cmd, stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await ping_proc.communicate()
outstr = stdout.decode()
if ping_proc.returncode == 0:
delay = int(re.search(r'(?:time=)([\d]*)', outstr).group(1)) if 'time=' in outstr else -1
if delay >= 0:
# print('{} {}ms'.format(host, delay))
return [host, delay]
return [host, None]
async def ping_all():
tasks = []
for i in range(1, 256):
ip = "192.168.1.{}".format(i)
task = asyncio.ensure_future(ping(ip))
tasks.append(task)
retList = await asyncio.gather(*tasks, return_exceptions=True)
retList = [x for x in retList if x[1] is not None]
retList.sort(key=lambda x: int(x[0].split('.')[-1]))
return retList
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
pingRet = loop.run_until_complete(ping_all())
for ip, d in pingRet:
print('{:<16s} {}ms'.format(ip, d))
My own method that combines several answers above:
def ping(host, show_log=False, package_count=1):
ping.param = "-n" if platform.system().lower() == 'windows' else "-c"
result = subprocess.run(['ping', ping.param, str(package_count), host],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
output = result.stdout
if show_log:
print('return code: ', result.returncode)
print(output.decode("utf-8"))
return result.returncode == 0 and (b'TTL=' in output or b'ttl=' in output)
Tested on OSX Monterey.