@chpo7234: Doch die werden (teilweise) asynchron abgearbeitet. Die Reihenfolge der Ausgabe kommt dadurch zustande das Du die Ergebnisse von den Thread-Exemplaren in der Reihenfolge abfragst in der sie erstellt und gestartet wurden. Da muss dann die Ausgabe eventuell auf ein Ergebnis warten, aber an der Gesamtlaufzeit ändert das nichts. Allerdings werden SNMP-Abfragen alle nacheinander im Hauptthread ausgeführt statt parallel, denn der Code wird ja erst ausgeführt wenn `status()` aufgerufen wird.
Anmerkungen zum Quelltext: Formatierung und Namensschreibweisen entsprechen teilweise nicht dem
Style Guide for Python Code.
Diese umrahmten Kommentare zerstören IMHO den Lesefluss ungemein. Der Inhalt ist zum Teil auch total überflüssig. Man muss vor einer Klasse nicht kommentieren dass das eine Klasse ist oder vor einer `__init__()` dass dort initialisiert wird.
Auf Modulebene gehört nur Code der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer `main()`-Funktion.
Keine nackten ``except:``\s verwenden. Da wird *alles* behandelt, auch Sachen mit denen Du gar nicht rechnest und für die die Behandlung unpassend ist.
Zwei führende Unterstriche bei Attributen sind dazu da um Namenskollisionen bei Mehrfachvererbung oder tiefen Typhierharchien zu vermeiden. Beides Sachen die weder hier noch allgemein in Python oft gemacht werden. Implementierungsdetails werden mit *einem* führenden Unterstrich gekennzeichnet.
Als ”(noch) nichts”-Wert sollte man keinen speziellen Wert nehmen der vom Typ her auch mit einem tatsächlichen Wert passen würde. In Python gibt es den Wert `None` für so etwas. Ausserdem ist hier ein Fehler. Die Anzahl wird bei Dir mit -1 initialisiert, aber wenn von ``ping`` keine Ausgabe kommt auf die der reguläre Ausdruck zutrifft, dann bleibt der Wert bei -1 und führt dann bei `status()` zu einem Rückgabewert der eher eine Ausnahme sein sollte.
`re.findall()` macht keinen Sinn wenn man nur den ersten Treffer überhaupt verarbeitet.
Namen sollte man erst definieren wenn man sie benötigt und nicht auf Vorrat irgendwo am Anfang einer Funktion. Das ist unübersichtlich und bei Programmänderungen vergisst man gerne mal solche Definitionen und sammelt so Müll an.
Man sollte keine Abkürzungen verwenden die nicht allgemein bekannt sind. Ich rätsele immer noch was `lv` bedeuten sollte. Auch `el` ist nicht schön.
`string_results` hat keinen Effekt. Eine leere Zeichenkette kann man so oft ”addieren” wie man lustig ist, das ändert nichts am Ergebnis. Der Name lässt auch vermuten, dass das eigentlich etwas anderes sein/werden sollte.
Wenn das Ergebnis an ein anderes Programm übermittelt werden soll, würde ich keinen Text verwenden und auch nicht krude HTML-Teile ausgeben sondern ein verbreitetes Serialisierungsformat verwenden wie beispielsweise JSON.
Ich lande dann bei so etwas (ungetestet):
Code: Alles auswählen
import json
import re
import socket
import sys
from collections import OrderedDict
from subprocess import check_output
from threading import Thread
import ipconvert
from pysnmp.entity.rfc3413.oneliner import cmdgen
ARROW = '=>'
def check_snmp(ip):
try:
reverse_dns = socket.gethostbyaddr(ip)[0]
except socket.error:
reverse_dns = ' '
command_generator = cmdgen.CommandGenerator()
error_indication, error_status, _, var_binding = command_generator.getCmd(
cmdgen.CommunityData('public'),
cmdgen.UdpTransportTarget((ip, 161), timeout=1, retries=0),
'1.3.6.1.2.1.1.1.0'
)
if error_indication or error_status:
return reverse_dns
else:
return '{0} {1} {2}'.format(reverse_dns, ARROW, var_binding[0][1])
class IpCheck(Thread):
RECEIVED_PACKAGES_RE = re.compile(r'(\d+) received')
def __init__(self, ip):
Thread.__init__(self)
self.ip = ip
self.result = None
def run(self):
match = self.RECEIVED_PACKAGES_RE.search(
check_output(['ping', '-q', '-c2', '-W1', self.ip])
)
successful_ping_count = int(match.group(1)) if match else 0
if successful_ping_count == 0:
self.result = 'no response'
elif successful_ping_count == 1:
self.result = 'alive, but 50% package loss'
elif successful_ping_count == 2:
self.result = check_snmp(self.ip)
else:
assert False
def ip_range(start, end):
return (
ipconvert.long2ip(i)
for i in range(ipconvert.ip2long(start), ipconvert.ip2long(end) + 1)
)
def main():
start = sys.argv[1]
end = sys.argv[2]
ip_checks = []
for ip in ip_range(start, end):
ip_check = IpCheck(ip)
ip_check.start()
ip_checks.append(ip_check)
result = OrderedDict()
for ip_check in ip_checks:
ip_check.join()
result[ip_check.ip] = ip_check.result
print(json.dumps(result))
if __name__ == '__main__':
main()