Multiple ping script in Python
Asked Answered
S

9

22

I'm unable to find any good easy to learn documentation on python and networking. In this instance, I'm just trying to make a easy script which I can ping a number of remote machines.

for ping in range(1,10):
   ip="127.0.0."+str(ping)
   os.system("ping -c 3 %s" % ip)

A simple script like that will ping the machines fine, but I'd like to get the script to returns 'active' 'no response' Which makes me think I'll have to look up the time module as well, I think time.sleep(5) and after that, there would be a break statement. Which makes me think there should be a while loop inside for. I'm not 100% sure, I could be going in the wrong direction completely :/ if anyone could help or point me in the direction of some documentation that'd be great.

Standoff answered 23/8, 2012 at 23:9 Comment(4)
I'm not sure why you think you need the time module? I'd suggest researching how to parse the STDOUT from a subprocess (which is what you should be using instead of os.system())Ratter
Try Scapy.Portative
Here is an example github.com/lbaby/javalearn/blob/master/shell/ppe.pyUpdraft
No do not use scapy, scapy is terrible for anything requiring either throughput or reliability... Both are required for monitoring applications.Lannielanning
K
31

Try subprocess.call. It saves the return value of the program that was used.

According to my ping manual, it returns 0 on success, 2 when pings were sent but no reply was received and any other value indicates an error.

# typo error in import
import subprocess

for ping in range(1,10):
    address = "127.0.0." + str(ping)
    res = subprocess.call(['ping', '-c', '3', address])
    if res == 0:
        print "ping to", address, "OK"
    elif res == 2:
        print "no response from", address
    else:
        print "ping to", address, "failed!"
Kalvin answered 23/8, 2012 at 23:21 Comment(2)
You'rw welcome. Remember to mark answers that helped you as accepted (click the green tickmark below the question vote tally), it signals to other visitors the answer was helpful. :-)Kalvin
subprocess.call() pings only one ip at a time. To ping multiple ips simultaneously subprocess.Popen() could be usedGarges
X
14

This script:

import subprocess
import os
with open(os.devnull, "wb") as limbo:
        for n in xrange(1, 10):
                ip="192.168.0.{0}".format(n)
                result=subprocess.Popen(["ping", "-c", "1", "-n", "-W", "2", ip],
                        stdout=limbo, stderr=limbo).wait()
                if result:
                        print ip, "inactive"
                else:
                        print ip, "active"

will produce something like this output:

192.168.0.1 active
192.168.0.2 active
192.168.0.3 inactive
192.168.0.4 inactive
192.168.0.5 inactive
192.168.0.6 inactive
192.168.0.7 active
192.168.0.8 inactive
192.168.0.9 inactive

You can capture the output if you replace limbo with subprocess.PIPE and use communicate() on the Popen object:

p=Popen( ... )
output=p.communicate()
result=p.wait()

This way you get the return value of the command and can capture the text. Following the manual this is the preferred way to operate a subprocess if you need flexibility:

The underlying process creation and management in this module is handled by the Popen class. It offers a lot of flexibility so that developers are able to handle the less common cases not covered by the convenience functions.

Xerophagy answered 23/8, 2012 at 23:15 Comment(1)
Please leave a comment with an explanation why you voted down, so the answer can be improved.Xerophagy
G
7

Thank you so much for this. I have modified it to work with Windows. I have also put a low timeout so, the IP's that have no return will not sit and wait for 5 seconds each. This is from hochl source code.

import subprocess
import os
with open(os.devnull, "wb") as limbo:
        for n in xrange(200, 240):
                ip="10.2.7.{0}".format(n)
                result=subprocess.Popen(["ping", "-n", "1", "-w", "200", ip],
                        stdout=limbo, stderr=limbo).wait()
                if result:
                        print ip, "inactive"
                else:
                        print ip, "active"

Just change the ip= for your scheme and the xrange for the hosts.

Galleywest answered 23/9, 2013 at 20:27 Comment(0)
R
4

I'm a beginner and wrote a script to ping multiple hosts.To ping multiple host you can use ipaddress module.

import ipaddress
from subprocess import Popen, PIPE

net4 = ipaddress.ip_network('192.168.2.0/24')
for x in net4.hosts():
    x = str(x)
    hostup = Popen(["ping", "-c1", x], stdout=PIPE)
    output = hostup.communicate()[0]
    val1 = hostup.returncode
 if val1 == 0:
    print(x, "is pinging")
 else:
    print(x, "is not responding")
Relict answered 16/1, 2016 at 16:53 Comment(0)
G
3

To ping several hosts at once you could use subprocess.Popen():

#!/usr/bin/env python3
import os
import time
from subprocess import Popen, DEVNULL

p = {} # ip -> process
for n in range(1, 100): # start ping processes
    ip = "127.0.0.%d" % n
    p[ip] = Popen(['ping', '-n', '-w5', '-c3', ip], stdout=DEVNULL)
    #NOTE: you could set stderr=subprocess.STDOUT to ignore stderr also

while p:
    for ip, proc in p.items():
        if proc.poll() is not None: # ping finished
            del p[ip] # remove from the process list
            if proc.returncode == 0:
                print('%s active' % ip)
            elif proc.returncode == 1:
                print('%s no response' % ip)
            else:
                print('%s error' % ip)
            break

If you can run as a root you could use a pure Python ping script or scapy:

from scapy.all import sr, ICMP, IP, L3RawSocket, conf

conf.L3socket = L3RawSocket # for loopback interface
ans, unans = sr(IP(dst="127.0.0.1-99")/ICMP(), verbose=0) # make requests
ans.summary(lambda (s,r): r.sprintf("%IP.src% is alive"))
Garges answered 24/8, 2012 at 1:11 Comment(0)
G
1
import subprocess
import os
'''
servers.txt contains ip address in following format
192.168.1.1
192.168.1.2
'''
    with open('servers.txt', 'r') as f:
        for ip in f:
            result=subprocess.Popen(["ping", "-c", "1", "-n", "-W", "2",    ip],stdout=f, stderr=f).wait()
            if result:
                print(ip, "inactive")
            else:
                print(ip, "active")
Gruchot answered 12/1, 2016 at 7:29 Comment(0)
W
1

Python actually has a really sweet method that will 'return an iterator over the usable hosts in the network'. (setting strict to false iterates over all IPs)

For example:

import subprocess
import ipaddress

subnet = ipaddress.ip_network('192.168.1.0/24', strict=False)
for i in subnet.hosts():
    i = str(i)
    subprocess.call(["ping", "-c1", "-n", "-i0.1", "-W1", i])

The wait interval (-i0.1) may be important for automations, even a one second timeout (-t1) can take forever over a .0/24

EDIT: So, in order to track ICMP (ping) requests, we can do something like this:

#!/usr/bin/env python

import subprocess
import ipaddress

alive = []
subnet = ipaddress.ip_network('192.168.1.0/23', strict=False)
for i in subnet.hosts():
    i = str(i)
    retval = subprocess.call(["ping", "-c1", "-n", "-i0.1", "-W1", i])
    if retval == 0:
        alive.append(i)
for ip in alive:
    print(ip + " is alive") 

Which will return something like:

192.168.0.1 is alive
192.168.0.2 is alive
192.168.1.1 is alive
192.168.1.246 is alive

i.e. all of the IPs responding to ICMP ranging over an entire /23-- Pretty cool!

Waistcloth answered 22/5, 2016 at 5:27 Comment(1)
FYI, I threw errors on this until specifying the IP address as being unicode: subnet = ipaddress.ip_network(u'192.168.1.0/23', strict=False)Blankly
S
0
import subprocess,os,threading,time
from queue import Queue
lock=threading.Lock()
_start=time.time()
def check(n):
    with open(os.devnull, "wb") as limbo:
                ip="192.168.21.{0}".format(n)
                result=subprocess.Popen(["ping", "-n", "1", "-w", "300", ip],stdout=limbo, stderr=limbo).wait()
                with lock:                    
                    if not result:
                        print (ip, "active")                       
    
def threader():
    while True:
        worker=q.get()
        check(worker)
        q.task_done()
q=Queue()

for x in range(255):
    t=threading.Thread(target=threader)
    t.daemon=True
    t.start()
for worker in range(1,255):
    q.put(worker)
q.join()
print("Process completed in: ",time.time()-_start)

I think this will be better one.

Spontaneity answered 2/4, 2016 at 23:56 Comment(2)
Thanks, It worked for me. Few chances are required to avoid errors: import Queue #in 2nd line q = Queue.Queue() #in 21st lineGuernica
Why the else: pass?Textual
G
0

I have done a few modifications in the above code with multithreading in python 2.7:

import subprocess,os,threading,time
import Queue

lock=threading.Lock()
_start=time.time()
def check(n):
    with open(os.devnull, "wb") as limbo:
                ip=n
                result=subprocess.Popen(["ping", "-n", "2", "-w", "300", ip],stdout=limbo, stderr=limbo).wait()
                with lock:
                    if not result:
                        print ip, "active"
                    else:
                        print ip, "Inactive"

def threader():
    while True:
        worker=q.get()
        check(worker)
        q.task_done()
q = Queue.Queue()

for x in range(255):
    t=threading.Thread(target=threader)
    t.daemon=True
    t.start()

ip = ["13.45.23.523", "13.35.23.523","23.23.56.346"]
for worker in ip:
    q.put(worker)
q.join()
print("Process completed in: ",time.time()-_start)
Guernica answered 12/2, 2021 at 20:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.