Measuring ping latency of a server - Python - python

I have a list of server IP addresses, I need to check if each one is online and how long the latency is.
I haven't found any straight forward ways of implementing this, and there seems to be a few problems in calculating latency accurately.
Any ideas?

If you are already comfortable with parsing strings, you can use the subprocess module to get the data you are looking for into a string, like this:
>>> import subprocess
>>> p = subprocess.Popen(["ping.exe","www.google.com"], stdout = subprocess.PIPE)
>>> print p.communicate()[0]
Pinging www.l.google.com [209.85.225.99] with 32 bytes of data:
Reply from 209.85.225.99: bytes=32 time=59ms TTL=52
Reply from 209.85.225.99: bytes=32 time=64ms TTL=52
Reply from 209.85.225.99: bytes=32 time=104ms TTL=52
Reply from 209.85.225.99: bytes=32 time=64ms TTL=52
Ping statistics for 209.85.225.99:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 59ms, Maximum = 104ms, Average = 72ms

Following hlovdal's suggestion to work with fping, here is my solution that I use for testing proxies. I only tried it under Linux. If no ping time could be measured, a big value is returned. Usage: print get_ping_time('<ip>:<port>').
import shlex
from subprocess import Popen, PIPE, STDOUT
def get_simple_cmd_output(cmd, stderr=STDOUT):
"""
Execute a simple external command and get its output.
"""
args = shlex.split(cmd)
return Popen(args, stdout=PIPE, stderr=stderr).communicate()[0]
def get_ping_time(host):
host = host.split(':')[0]
cmd = "fping {host} -C 3 -q".format(host=host)
res = [float(x) for x in get_simple_cmd_output(cmd).strip().split(':')[-1].split() if x != '-']
if len(res) > 0:
return sum(res) / len(res)
else:
return 999999

This post is a bit old and I think better ways exists today. I'm new to python but here's what I did on my project:
from pythonping import ping
def ping_host(host):
ping_result = ping(target=host, count=10, timeout=2)
return {
'host': host,
'avg_latency': ping_result.rtt_avg_ms,
'min_latency': ping_result.rtt_min_ms,
'max_latency': ping_result.rtt_max_ms,
'packet_loss': ping_result.packet_loss
}
hosts = [
'192.168.48.1',
'192.168.48.135'
]
for host in hosts:
print(ping_host(host))
Result:
{'host': '192.168.48.1', 'avg_latency': 2000.0, 'min_latency': 2000, 'max_latency': 2000, 'packet_loss': 1.0}
{'host': '192.168.48.135', 'avg_latency': 42.67, 'min_latency': 41.71, 'max_latency': 44.17, 'packet_loss': 0.0}
You can find the pythonping library here: https://pypi.org/project/pythonping/

If you want to avoid implementing all the network communication details you could probably try to build something on top of fping:
fping is a like program which uses the
Internet Control Message Protocol
(ICMP) echo request to determine if a
target host is responding. fping
differs from ping in that you can
specify any number of targets on the
command line, or specify a file
containing the lists of targets to
ping. Instead of sending to one target
until it times out or replies, fping will send
out a ping packet and move on to the
next target in a round-robin fashion.

https://github.com/matthieu-lapeyre/network-benchmark My solution based on the work of FlipperPA: https://github.com/FlipperPA/latency-tester
import numpy
import pexpect
class WifiLatencyBenchmark(object):
def __init__(self, ip):
object.__init__(self)
self.ip = ip
self.interval = 0.5
ping_command = 'ping -i ' + str(self.interval) + ' ' + self.ip
self.ping = pexpect.spawn(ping_command)
self.ping.timeout = 1200
self.ping.readline() # init
self.wifi_latency = []
self.wifi_timeout = 0
def run_test(self, n_test):
for n in range(n_test):
p = self.ping.readline()
try:
ping_time = float(p[p.find('time=') + 5:p.find(' ms')])
self.wifi_latency.append(ping_time)
print 'test:', n + 1, '/', n_test, ', ping latency :', ping_time, 'ms'
except:
self.wifi_timeout = self.wifi_timeout + 1
print 'timeout'
self.wifi_timeout = self.wifi_timeout / float(n_test)
self.wifi_latency = numpy.array(self.wifi_delay)
def get_results(self):
print 'mean latency', numpy.mean(self.wifi_latency), 'ms'
print 'std latency', numpy.std(self.wifi_latency), 'ms'
print 'timeout', self.wifi_timeout * 100, '%'
if __name__ == '__main__':
ip = '192.168.0.1'
n_test = 100
my_wifi = WifiLatencyBenchmark(ip)
my_wifi.run_test(n_test)
my_wifi.get_results()
Github repository:
https://github.com/matthieu-lapeyre/network-benchmark

thanks from Jabba but that code doesn't work correctly for me so i change something like following
import shlex
from subprocess import Popen, PIPE, STDOUT
def get_simple_cmd_output(cmd, stderr=STDOUT):
"""
Execute a simple external command and get its output.
"""
args = shlex.split(cmd)
return Popen(args, stdout=PIPE, stderr=stderr).communicate()[0]
def get_ping_time(host):
host = host.split(':')[0]
cmd = "fping {host} -C 3 -q".format(host=host)
# result = str(get_simple_cmd_output(cmd)).replace('\\','').split(':')[-1].split() if x != '-']
result = str(get_simple_cmd_output(cmd)).replace('\\', '').split(':')[-1].replace("n'", '').replace("-",
'').replace(
"b''", '').split()
res = [float(x) for x in result]
if len(res) > 0:
return sum(res) / len(res)
else:
return 999999
def main():
# sample hard code for test
host = 'google.com'
print([host, get_ping_time(host)])
host = 'besparapp.com'
print([host, get_ping_time(host)])
if __name__ == '__main__':
main()

Related

Multiple IP addresse PING

The below code works perfectly if the input file ip_file.txt have the following format.
8.8.8.8
www.google.com
www.yahoo.com
www.microsoft.com
But how can I ping the IPs if the input is something like this and write the output same in format.
8.8.8.8, www.google.com
www.yahoo.com,www.microsoft.com
My code is given below:
import subprocess
import threading
import time
import re
timestr = time.strftime("%Y-%m-%d %H%M%S")
timesec = time.strftime("%Y-%m-%d%H:%M:%S")
raw_list = []
def ping(host):
results_file = open("results_bng_" + str(timestr) + ".txt", "a")
p = subprocess.Popen(["ping", host, "-n", "5"], shell=True, universal_newlines=True, stdout=subprocess.PIPE)
response = p.communicate()[0]
for i in response.split("\n"):
para =i.split("=")
# print(para)
try:
if para[0].strip() =="Minimum":
latency =para[3].strip()
print(latency)
latfin = re.findall('\d+', latency)
latfin1 = latfin[0]
except:
print("time run")
if "Received = 1" and "Approximate" in response:
print(f"UP {host} Ping Successful")
results_file.write(f"{host},UP,{latfin1},{timesec}"+ "\n")
else:
print(f"Down {host} Ping Unsuccessful")
results_file.write(f"{host},Down,0,{timesec}" + "\n")
results_file.close()
with open(r'bng.txt', "r") as server_list_file:
hosts = server_list_file.read()
hosts_list =hosts.split('\n')
num_threads = 1
number = 0
while number< len(hosts_list):
# print(number)
for i in range(num_threads):
t = threading.Thread(target=ping, args=(hosts_list[number+i],))
t.start()
t.join()
number = number +1
You could replace each newline character with a comma and split at each comma:
bng.txt:
8.8.8.8, www.google.com
www.yahoo.com,www.microsoft.com
Code:
with open(r'bng.txt', "r") as server_list_file:
hosts = server_list_file.read()
hosts_list = hosts.replace('\n', ',').split(',')
for host in hosts_list:
print(host.strip()) # strip remaining whitespaces
Out:
8.8.8.8
www.google.com
www.yahoo.com
www.microsoft.com
Pings are specific IP packets that can only be sent to one ip at a time. There are special IP which are meant for broadcasting. For example, you could direct your ping at a specific subnet and the devices connected to that subnet could all choose to answer to a ping. Note that most routers or IP stacks do not answer to such broadcast pings nowadays as they could be used to discover the devices that are connected to the subnet.
After you open your file you need to do a for loop and read each line at a time and split based on comma. That will ultimately give you a list of all single IPs / hosts to ping. Something like.
listOfAllIPs = []
for line in file:
x = line.split(',') ## this makes x a list
listOfAllIPs = listOfAllIPs + x
After that runs you should be able to use listOfAllIPs as your input. It will have 1 IP or host per item. Just iterate through.
this will be useful for you
import os
import subprocess
list = []
with open('./ip.txt', 'r') as f:
ip = f.read().split(',')
list.append(ip)
for i in range(len(list[0])):
ip = list[0][i]
print(30*'-')
if subprocess.Popen(["ping", "-n", "1", "-w", "200", ip], shell=True).wait() == 1: print('active', ip)
else: print('inactive', ip)

How to use subprocess in a RxPY map correctly?

I am trying to use RxPY to scan the IP to see which hosts are up.
However, currently it returns empty.
For ping(ip), if I simply return ip, it will return a list of IP address.
from reactivex import operators as ops
import reactivex as rx
import subprocess
# If I change to this version, it will return a list of IP address.
# def ping(ip):
# return ip
def ping(ip):
retval = subprocess.call(["ping", "-c1", "-n", "-i0.1", "-W1", ip])
print("Here!") # It never reached here.
if retval == 0:
return ip # host is up
else:
return "" # host is down
if __name__ == "__main__":
ip_list = ["192.168.1.1", "192.168.1.2"]
rx.of(ip_list).pipe(
ops.map(lambda ip: ping(ip)),
).subscribe(lambda x: print(list(x)))
The line of subprocess.call is totally skipped.
I am thinking it might be related with async, however in this case, the function subprocess.call seems not an async function.
How to use subprocess correctly? Any guide would be appreciate!
I found a solution. The idea is wrapping subprocess.call as an Observable.
After creating my custom operator based on the doc, now it works!
import reactivex as rx
import subprocess
def ping():
def _ping(source):
def subscribe(observer, scheduler=None):
def on_next(ip):
retval = subprocess.call(["ping", "-c1", "-n", "-i0.1", "-W1", ip])
if retval == 0: # host is up
observer.on_next(ip)
else: # host is down
observer.on_next("")
return source.subscribe(
on_next,
observer.on_error,
observer.on_completed)
return rx.create(subscribe)
return _ping
if __name__ == "__main__":
ip_list = ['192.168.1.1', '192.168.1.2']
rx.of(*ip_list).pipe(
ping(),
).subscribe(lambda x: x)
It will print something like this now
PING 192.168.1.1 (192.168.1.1): 56 data bytes
--- 192.168.1.1 ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss
PING 192.168.1.2 (192.168.1.2): 56 data bytes
--- 192.168.1.2 ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss

I need help completing my code. Note I am a beginner in Python

I am trying to develop a script which sends an email about checking ping regularly at one hour interval of time. I am using Python to program this script and I cannot create a log file to keep the ping logs which I need to mail. I'm new to using subprocess module and its functions.
import threading
import os
def check_ping():
threading.Timer(5.0, check_ping).start()
hostname = "www.google.com"
response = os.system("ping -c 4 " + hostname)
'''
def trace_route():
threading.Timer(5.0, trace_route).start()
hostname = "www.google.com"
response = os.system("traceroute" + hostname)
'''
check_ping()
#trace_route()
output = check_ping()
file = open("sample.txt","a")
file.write(output)
file.close()
import os, platform
import threading
def check_ping():
threading.Timer(10.0,check_ping).start()
hostname = "www.google.com"
response = os.system("ping " + ("-n 1 " if platform.system().lower()=="windows" else "-c 1 ") + hostname)
# and then check the response...
if response == 0:
pingstatus = "Network Active"
else:
pingstatus = "Network Error"
return pingstatus
pingstatus = check_ping()
This is what I came up with:
using subprocess instead of os.system
added timeout of 8 seconds
writing to csv file instead of txt file
added timestamps to csv file, without which I don't really see the point of logging in the first place
import os
import threading
import time
from subprocess import Popen, PIPE
def check_ping():
threading.Timer(10.0,check_ping).start()
# Get current time
timestamp = int(time.time())
# Build the command
hostname = "www.google.com"
if os.name == 'nt':
command = ['ping', '-n', '1', hostname]
else:
command = ['ping', '-c', '1', hostname]
# Create process
pingProcess = Popen(command, stdout=PIPE, stderr=PIPE)
try:
# Timeout 8 seconds, to avoid overlap with the next ping command
outs, errs = pingProcess.communicate(timeout=8)
except TimeoutExpired:
# If timed out, kill
pingProcess.kill()
outs, errs = pingProcess.communicate()
# Get the return code of the process
response = pingProcess.returncode
# and then check the response...
# These four lines can be removed, they are just to see if the system
# works.
if response == 0:
print("Network Active")
else:
print("Network Error")
# You most likely want a CSV file, as most programs accept this file type,
# including Microsoft Excel and LibreOffice Calc
# Further, I'm sure you want timestamps with the results.
file = open("ping.csv","a")
file.write(str(timestamp) + "," + str(response) + "\n")
file.close()
check_ping()
Here is another version without using the system's ping command, but instead using a python library for pinging. This ensures that the code works on all operating systems:
import threading
import time
from ping3 import ping
def check_ping():
threading.Timer(10.0,check_ping).start()
# Get current time
timestamp = int(time.time())
# Build the command
hostname = "www.google.com"
# Run ping
ping_result = ping(hostname, timeout=8)
ping_success = False if ping_result is None else True
# and then check the response...
# These four lines can be removed, they are just to see if the system
# works.
if ping_success:
print("Network Active (" + str(ping_result) + ")")
else:
print("Network Error")
# You most likely want a CSV file, as most programs accept this file type,
# including Microsoft Excel and LibreOffice Calc
# Further, I'm sure you want timestamps with the results.
file = open("ping.csv", "a")
ping_value_str = str(ping_result) if ping_success else "NaN"
file.write(str(timestamp) + "," + ("0" if ping_success else "1") + "," + ping_value_str + "\n")
file.close()
check_ping()

Sending DHCP Discover using python scapy

I am new to python and learning some network programming, I wish to send an DHCP Packet through my tap interface to my DHCP server and expecting some response from it. I tried with several packet building techniques such a structs and ctypes and ended up with using scapy. Here I am able to send DHCP Packet but unable to get any response from the DHCP server(Analyzed using wireshark and tcpdump)..My packet looked like same as original DHCP packet but failed to get response. Here is my code
import socket
from scapy.all import *
def main():
if len(sys.argv)<3:
print " fewer arguments."
sys.exit(1)
else:
tap_interface = sys.argv[1]
src_mac_address = sys.argv[2]
ethernet = Ether(dst='ff:ff:ff:ff:ff:ff',src=src_mac_address,type=0x800)
ip = IP(src ='0.0.0.0',dst='255.255.255.255')
udp =UDP (sport=68,dport=67)
fam,hw = get_if_raw_hwaddr(tap_interface)
bootp = BOOTP(chaddr = hw, ciaddr = '0.0.0.0',xid = 0x01020304,flags= 1)
dhcp = DHCP(options=[("message-type","discover"),"end"])
packet = ethernet / ip / udp / bootp / dhcp
fd = open('/dev/net/tun','r+')
TUNSETIFF = 0x400454ca
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000
mode = IFF_TAP | IFF_NO_PI
ifr = struct.pack('16sH', tap_interface, IFF_TAP | IFF_NO_PI)
fcntl.ioctl(fd,TUNSETIFF,ifr)
while True:
sendp(packet, iface = tap_interface)
time.sleep(10)
if __name__ == '__main__':
main()
Is there any other ways of achieving this? If so please do mention them as well.
Thanks in Advance.
Solved ! I had the same problem,
The problem I think was on the srp() function, it can't receive packets on port 68, but I've created a new function with a new thread that sniffs BOOTP messages and displays the packet fields.
you can simulate it :
sniff(iface=myiface, filter="port 68 and port 67")
then send the packet using srp() or sendp() func :)
NOTE:
I have used multithreading mechanism cause my program sends messages and sniffs if a rogue DHCP Server is on the network
I am not sure if this would qualify as an answer, but we use scapy to simulate DHCP server/client exchange, and the following does the job for us:
discover = Ether(dst='ff:ff:ff:ff:ff:ff', src=cliMAC, type=0x0800) / IP(src='0.0.0.0', dst='255.255.255.255') / UDP(dport=67,sport=68) / BOOTP(op=1, chaddr=cliMACchaddr) / DHCP(options=[('message-type','discover'), ('end')])
The main difference between my code and yours seem to be how the BOOTP header is defined. Maybe you could try my packet definition and see if it works?
Here is an example that I did that gets a dhcp address and assigns it to an ip interface:
My rough POC, while creating code for my project:
#!/usr/bin/python
from scapy.all import Ether,IP,UDP,DHCP,BOOTP,get_if_raw_hwaddr,get_if_hwaddr,conf,sniff,sendp
from pyroute2 import IPDB
from Queue import Empty
from multiprocessing import Process, Queue, Manager
from wpa_supplicant.core import WpaSupplicantDriver
from twisted.internet.selectreactor import SelectReactor
import threading
import time
import errno
import sys
import types
import netifaces
import dbus
import json
import re
class PythonDHCPScanner:
def change_ip(self,ipObject,netInterface):
ipdb = IPDB()
ips= ipdb.interfaces[self.get_interface(netInterface)]
ipAddrs = ips.ipaddr.ipv4[0]
ips.del_ip(ipAddrs['address'],ipAddrs['prefixlen'])
ips.add_ip(ipObject['ipAddr'],24)
ipdb.commit()
ipdb.routes.add(dst="default",gateway=ipObject['router'])
ipdb.commit()
def queue_get_all(self):
items = []
maxItems = 50
for numOfItemsRetrieved in range(0, maxItems):
try:
items.append(self.q.get_nowait())
except Empty, e:
break
return items
def __init__(self):
self.net_iface = netifaces.interfaces()
def dhcp_print(self,pkt):
self.q.put(str(pkt))
def get_interface(self,number):
return str(self.net_iface[number].decode())
def get_interfaces(self):
return self.net_iface
def get_dhcp_object(self,interfaceNumber):
self.q = Manager().Queue()
c = Process(target=self.callSniffer,args=(interfaceNumber,)).start()
time.sleep(0.1)
p = Process(target=self.callPacket(interfaceNumber)).start()
time.sleep(5)
if c is not None:
c.join()
dhcp = {}
for strPkt in self.queue_get_all():
try:
pkt = Ether(strPkt)
pkt.show()
if pkt[Ether].dst == get_if_hwaddr(self.get_interface(interfaceNumber)):
if pkt[DHCP]:
if pkt.getlayer(DHCP).fields['options'][0][1] == 2:
if pkt[IP]:
dhcp['ipAddr'] = pkt[IP].dst
for option in pkt.getlayer(DHCP).fields['options']:
if option == 'end':
break
dhcp[option[0]] = option[1]
print dhcp['router']
print dhcp['subnet_mask']
break
except:
continue
return dhcp
def callSniffer(self,interfaceNumber):
inter = self.get_interface(interfaceNumber)
conf.iface = inter
print inter
sniff(iface=inter,filter="udp",prn=self.dhcp_print, timeout=10)
def callPacket(self,interfaceNumber):
inter = self.get_interface(interfaceNumber)
print inter
fam,hw = get_if_raw_hwaddr(inter)
macaddress= get_if_hwaddr(inter)
conf.iface = inter
ethernet = Ether(dst="ff:ff:ff:ff:ff:ff",src=macaddress,type=0x800)
ip = IP(src="0.0.0.0",dst="255.255.255.255")
udp = UDP(sport=68,dport=67)
bootp = BOOTP(chaddr =hw,xid=0x10000000)
dhcp = DHCP(options=[("message-type","discover"),("end")])
packet=ethernet/ip/udp/bootp/dhcp
sendp(packet,iface=inter)
# get dhcp object
dave = PythonDHCPScanner()
dhcpObject = dave.get_dhcp_object(3)
# Pick interface number 3 on my box
time.sleep(1)
for dhcpKey in dhcpObject.keys():
print str(dhcpKey) + ":" + str(dhcpObject[dhcpKey])
time.sleep(1)
dave.change_ip(dhcpObject,3)

List of IP addresses/hostnames from local network in Python

How can I get a list of the IP addresses or host names from a local network easily in Python?
It would be best if it was multi-platform, but it needs to work on Mac OS X first, then others follow.
Edit: By local I mean all active addresses within a local network, such as 192.168.xxx.xxx.
So, if the IP address of my computer (within the local network) is 192.168.1.1, and I have three other connected computers, I would want it to return the IP addresses 192.168.1.2, 192.168.1.3, 192.168.1.4, and possibly their hostnames.
If by "local" you mean on the same network segment, then you have to perform the following steps:
Determine your own IP address
Determine your own netmask
Determine the network range
Scan all the addresses (except the lowest, which is your network address and the highest, which is your broadcast address).
Use your DNS's reverse lookup to determine the hostname for IP addresses which respond to your scan.
Or you can just let Python execute nmap externally and pipe the results back into your program.
Update: The script is now located on github.
I wrote a small python script, that leverages scapy's arping().
If you know the names of your computers you can use:
import socket
IP1 = socket.gethostbyname(socket.gethostname()) # local IP adress of your computer
IP2 = socket.gethostbyname('name_of_your_computer') # IP adress of remote computer
Otherwise you will have to scan for all the IP addresses that follow the same mask as your local computer (IP1), as stated in another answer.
I have collected the following functionality from some other threads and it works for me in Ubuntu.
import os
import socket
import multiprocessing
import subprocess
def pinger(job_q, results_q):
"""
Do Ping
:param job_q:
:param results_q:
:return:
"""
DEVNULL = open(os.devnull, 'w')
while True:
ip = job_q.get()
if ip is None:
break
try:
subprocess.check_call(['ping', '-c1', ip],
stdout=DEVNULL)
results_q.put(ip)
except:
pass
def get_my_ip():
"""
Find my IP address
:return:
"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ip = s.getsockname()[0]
s.close()
return ip
def map_network(pool_size=255):
"""
Maps the network
:param pool_size: amount of parallel ping processes
:return: list of valid ip addresses
"""
ip_list = list()
# get my IP and compose a base like 192.168.1.xxx
ip_parts = get_my_ip().split('.')
base_ip = ip_parts[0] + '.' + ip_parts[1] + '.' + ip_parts[2] + '.'
# prepare the jobs queue
jobs = multiprocessing.Queue()
results = multiprocessing.Queue()
pool = [multiprocessing.Process(target=pinger, args=(jobs, results)) for i in range(pool_size)]
for p in pool:
p.start()
# cue hte ping processes
for i in range(1, 255):
jobs.put(base_ip + '{0}'.format(i))
for p in pool:
jobs.put(None)
for p in pool:
p.join()
# collect he results
while not results.empty():
ip = results.get()
ip_list.append(ip)
return ip_list
if __name__ == '__main__':
print('Mapping...')
lst = map_network()
print(lst)
For OSX (and Linux), a simple solution is to use either os.popen or os.system and run the arp -a command.
For example:
import os
devices = []
for device in os.popen('arp -a'): devices.append(device)
This will give you a list of the devices on your local network.
I found this network scanner in python article and wrote this short code. It does what you want! You do however need to know accessible ports for your devices. Port 22 is ssh standard and what I am using. I suppose you could loop over all ports. Some defaults are:
linux: [20, 21, 22, 23, 25, 80, 111, 443, 445, 631, 993, 995]
windows: [135, 137, 138, 139, 445]
mac: [22, 445, 548, 631]
import socket
def connect(hostname, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.setdefaulttimeout(1)
result = sock.connect_ex((hostname, port))
sock.close()
return result == 0
for i in range(0,255):
res = connect("192.168.1."+str(i), 22)
if res:
print("Device found at: ", "192.168.1."+str(i) + ":"+str(22))
EDIT by TheLizzard:
Using the code above and adding threading:
from threading import Thread, Lock
from time import perf_counter
from sys import stderr
from time import sleep
import socket
# I changed this from "192.168.1.%i" to "192.168.0.%i"
BASE_IP = "192.168.0.%i"
PORT = 80
class Threader:
"""
This is a class that calls a list of functions in a limited number of
threads. It uses locks to make sure the data is thread safe.
Usage:
from time import sleep
def function(i):
sleep(2)
with threader.print_lock:
print(i)
threader = Threader(10) # The maximum number of threads = 10
for i in range(20):
threader.append(function, i)
threader.start()
threader.join()
This class also provides a lock called: `<Threader>.print_lock`
"""
def __init__(self, threads=30):
self.thread_lock = Lock()
self.functions_lock = Lock()
self.functions = []
self.threads = []
self.nthreads = threads
self.running = True
self.print_lock = Lock()
def stop(self) -> None:
# Signal all worker threads to stop
self.running = False
def append(self, function, *args) -> None:
# Add the function to a list of functions to be run
self.functions.append((function, args))
def start(self) -> None:
# Create a limited number of threads
for i in range(self.nthreads):
thread = Thread(target=self.worker, daemon=True)
# We need to pass in `thread` as a parameter so we
# have to use `<threading.Thread>._args` like this:
thread._args = (thread, )
self.threads.append(thread)
thread.start()
def join(self) -> None:
# Joins the threads one by one until all of them are done.
for thread in self.threads:
thread.join()
def worker(self, thread:Thread) -> None:
# While we are running and there are functions to call:
while self.running and (len(self.functions) > 0):
# Get a function
with self.functions_lock:
function, args = self.functions.pop(0)
# Call that function
function(*args)
# Remove the thread from the list of threads.
# This may cause issues if the user calls `<Threader>.join()`
# But I haven't seen this problem while testing/using it.
with self.thread_lock:
self.threads.remove(thread)
start = perf_counter()
# I didn't need a timeout of 1 so I used 0.1
socket.setdefaulttimeout(0.1)
def connect(hostname, port):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
result = sock.connect_ex((hostname, port))
with threader.print_lock:
if result == 0:
stderr.write(f"[{perf_counter() - start:.5f}] Found {hostname}\n")
threader = Threader(10)
for i in range(255):
threader.append(connect, BASE_IP%i, PORT)
threader.start()
threader.join()
print(f"[{perf_counter() - start:.5f}] Done searching")
input("Press enter to exit.\n? ")
Try:
import socket
print ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])
I have done following code to get the IP of MAC known device. This can be modified accordingly to obtain all IPs with some string manipulation. Hope this will help you.
#running windows cmd line statement and put output into a string
cmd_out = os.popen("arp -a").read()
line_arr = cmd_out.split('\n')
line_count = len(line_arr)
#search in all lines for ip
for i in range(0, line_count):
y = line_arr[i]
z = y.find(mac_address)
#if mac address is found then get the ip using regex matching
if z > 0:
ip_out= re.search('[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+', y, re.M | re.I)
I have just had the problem. I solved it like this:
import kthread #pip install kthread
from time import sleep
import subprocess
def getips():
ipadressen = {}
def ping(ipadresse):
try:
outputcap = subprocess.run([f'ping', ipadresse, '-n', '1'], capture_output=True) #sends only one package, faster
ipadressen[ipadresse] = outputcap
except Exception as Fehler:
print(Fehler)
t = [kthread.KThread(target = ping, name = f"ipgetter{ipend}", args=(f'192.168.0.{ipend}',)) for ipend in range(255)] #prepares threads
[kk.start() for kk in t] #starts 255 threads
while len(ipadressen) < 255:
print('Searching network')
sleep(.3)
alldevices = []
for key, item in ipadressen.items():
if not 'unreachable' in item.stdout.decode('utf-8') and 'failure' not in item.stdout.decode('utf-8'): #checks if there wasn't neither general failure nor 'unrechable host'
alldevices.append(key)
return alldevices
allips = getips() #takes 1.5 seconds on my pc
One of the answers in this question might help you. There seems to be a platform agnostic version for python, but I haven't tried it yet.
Here is a small tool scanip that will help you to get all ip addresses and their corresponding mac addresses in the network (Works on Linux).
https://github.com/vivkv/scanip

Categories