Portscanner mit pcap

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
BlackJack

@elactic: Noch mal allgemeine Anmerkungen zum Quelltext von mir:

Es gibt eine Menge Zeilen die länger als 80 Zeichen sind. Ich denke sehr häufig sind es lange Kommentare die ans Ende einer Zeile gesetzt wurden. Das ist je nach Umbruchverhalten der Anzeige schwer bis sehr schwer zu lesen. Und dabei sollte man nicht nur an den eigenen Editor denken, sondern auch an die Editoren anderer Leute, das Konsolenfenster, Textfelder in GUIs für Versionskontrollsoftware, E-Mail-Clients, Webseiten, und so weiter. Eben alles wo Quelltexte/Patches noch so angezeigt werden und gelesen werden müssen.

Einige von den Kommentaren sind auch überflüssig. Ein Kommentar sollte einen Mehrwert zum Code bieten. Einige bei Dir sagen nochmal das Offensichtliche was schon im Code steht. Was Code macht sollte man nur kommentieren wenn der Code zu komplex ist und man ihn nicht einfacher bekommt. Kommentare sind eher dazu da zu beschreiben warum der Code das tut was er tut.

Die `min()`/`max()`-Funktionen kann man auch mit mehreren Argumenten aufrufen. Also statt ``min([a, b])`` geht auch ``min(a, b)``. IMHO ist das Beschränken der Ports da nicht an der richtigen Stelle beziehungsweise generell nicht gut. In der `__init__()` würde ich eher auf die Grenzen prüfen und auch ob `port_start` kleiner oder gleich `port_end` ist, und falls nicht eine Ausnahme auslösen. Das wäre schliesslich eine fehlerhafte Eingabe vom Benutzer.

Den Code im ``if __name__ == '__main__':``-Zweig solltest Du noch in eine Funktion stecken. Sonst hast Du sowohl in Funktionen als auch auf Modulebene einige identische Namen definiert. So etwas kann zu subtilen Fehlern führen, wenn man dann doch aus versehen mal auf einen Namen auf Modulebene zugreift, den man in einer Methode für einen Lokalen hält.

``except`` und ``print`` sind keine Funktionen. ``print`` ist das erst in Python 3, da Du aber `random.shuffle()` auf das Ergebnis von `range()` anwendest, muss das Python 2-Quelltext sein:

Code: Alles auswählen

>>> import random
>>> random.shuffle(range(42))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.1/random.py", line 270, in shuffle
    x[i], x[j] = x[j], x[i]
TypeError: 'range' object does not support item assignment
Also weg mit den überflüssigen Klammern. Oder Du importierst `print()` als Funktion aus dem `__future__`-Modul.

Beide Portscanner sind überflüssigerweise Klassen. Du nutzt nirgends den Umstand dass das eine Klasse ist auch tatsächlich aus. Klassen sind kein Selbstszweck und in Python auch nicht das Mittel um einen Namensraum für einfache Funktionen zu schaffen. Dafür gibt es Module.

Statt einer `Semaphore` hätte man auch ein `Lock` nehmen können. Und die kann man mit der ``with``-Anweisung kombinieren. Das ist sicherer.

Beide Scanner enthalten ähnlichen Quelltext, den man heraus ziehen könnte.

Es gibt in Python keine ``private``-Methoden. Auf Modulebene schon gar nicht. Implementierungsdetails werden mit *einem* führenden Unterstrich gekennzeichnet.

Die Argumente könnte man mit `argparse` verarbeiten.
elactic
User
Beiträge: 18
Registriert: Mittwoch 16. Dezember 2009, 14:49

BlackJack hat geschrieben: Es gibt eine Menge Zeilen die länger als 80 Zeichen sind. Ich denke sehr häufig sind es lange Kommentare die ans Ende einer Zeile gesetzt wurden. Das ist je nach Umbruchverhalten der Anzeige schwer bis sehr schwer zu lesen. Und dabei sollte man nicht nur an den eigenen Editor denken, sondern auch an die Editoren anderer Leute, das Konsolenfenster, Textfelder in GUIs für Versionskontrollsoftware, E-Mail-Clients, Webseiten, und so weiter. Eben alles wo Quelltexte/Patches noch so angezeigt werden und gelesen werden müssen.
Wohl wahr.
Kannst du mir sagen, wie ich Anweisungen über mehrere Zeilen ersterecke?
Ich sehe hin und wieder mal sachen wie

Code: Alles auswählen

befehl( arg1= x,
		arg2= y, 
		arg3= z)
Aber wenn ich sowas selbst versuche...
BlackJack hat geschrieben: Einige von den Kommentaren sind auch überflüssig. Ein Kommentar sollte einen Mehrwert zum Code bieten. Einige bei Dir sagen nochmal das Offensichtliche was schon im Code steht. Was Code macht sollte man nur kommentieren wenn der Code zu komplex ist und man ihn nicht einfacher bekommt. Kommentare sind eher dazu da zu beschreiben warum der Code das tut was er tut.
Ja das war eine Arbeit für die Uni mit der klaren Anweisung, ALLES zu kommentieren.
Da schreib ich dann einen (unsinnigen) Kommentar mehr als einen zu wenig (hätte es für euch natürlich rausnehmen können).
BlackJack hat geschrieben: Die `min()`/`max()`-Funktionen kann man auch mit mehreren Argumenten aufrufen. Also statt ``min([a, b])`` geht auch ``min(a, b)``.
Ok da habe ich das Falsche aus der API abgeschrieben ;)
BlackJack hat geschrieben: IMHO ist das Beschränken der Ports da nicht an der richtigen Stelle beziehungsweise generell nicht gut. In der `__init__()` würde ich eher auf die Grenzen prüfen und auch ob `port_start` kleiner oder gleich `port_end` ist, und falls nicht eine Ausnahme auslösen. Das wäre schliesslich eine fehlerhafte Eingabe vom Benutzer.
Ganz idiotensicher ist es nicht, stimmt. Aber ich wollte alle möglichen Fehlerfälle (also zB auch die Frage, ob der gesuchte Port überhaupt existiert) so früh wie irgendwie möglich abfangen.
Aber ob ich es in Klassen hätte packen sollen...
BlackJack hat geschrieben: Den Code im ``if __name__ == '__main__':``-Zweig solltest Du noch in eine Funktion stecken. Sonst hast Du sowohl in Funktionen als auch auf Modulebene einige identische Namen definiert. So etwas kann zu subtilen Fehlern führen, wenn man dann doch aus versehen mal auf einen Namen auf Modulebene zugreift, den man in einer Methode für einen Lokalen hält.
Warte mal. Variablen auf Modulebene sind in Funktionen sichtbar?
BlackJack hat geschrieben: ``except`` und ``print`` sind keine Funktionen. ``print`` ist das erst in Python 3, da Du aber `random.shuffle()` auf das Ergebnis von `range()` anwendest, muss das Python 2-Quelltext sein:

Code: Alles auswählen

>>> import random
>>> random.shuffle(range(42))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.1/random.py", line 270, in shuffle
    x[i], x[j] = x[j], x[i]
TypeError: 'range' object does not support item assignment
Also weg mit den überflüssigen Klammern. Oder Du importierst `print()` als Funktion aus dem `__future__`-Modul.
Ahhh naja ich schreibe eigentlich lieber Python 3. Ich finde es 'schöner' print als Funktion aufzurufen. Bei dieser Übung bin ich leider auf das bekannte Problem von Python 3 gestoßen, nämlich dass viele Bibliotheken nicht existieren.
Bin deshalb auf Python 2.7 umgeschwänkt, habe mir mein print() aber beibehalten...
BlackJack hat geschrieben: Statt einer `Semaphore` hätte man auch ein `Lock` nehmen können. Und die kann man mit der ``with``-Anweisung kombinieren. Das ist sicherer.
Oh naja ich hatte irgendwo vorher einen Anwendungsfall, bei dem ich mehrere gleichzeitige Ausführungen zulassen wollte (weiß auch nicht mehr was das war).
Un da habe ich einfach weiterhin die Semaphore genommen. Semaphore(1) und Lock() sind doch eigentlich das gleiche oder? (natürlich nicht in der Implementierung, aber vom äußeren Verhalten)
Was meinst du mit with?
BlackJack hat geschrieben: Es gibt in Python keine ``private``-Methoden. Auf Modulebene schon gar nicht. Implementierungsdetails werden mit *einem* führenden Unterstrich gekennzeichnet. Druckansicht
Ok auf Modulebene war das tatsächlich dämlich.
Aber auf Klassenebene?
Ich dachte das ginge (auch wenn sich "The Guido" tierisch drüber aufregt).
Ich hatte immer im Kopf, dass ein Unterstrich dem entwickler anzeigt, dass er es nicht nutzen SOLL, und dass der doppelte Unterstrick die Methode bzw Variable tatsächlich private macht....
BlackJack hat geschrieben: Die Argumente könnte man mit `argparse` verarbeiten.
Sieht cool aus, danke =)
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

elactic hat geschrieben:Ich hatte immer im Kopf, dass ein Unterstrich dem entwickler anzeigt, dass er es nicht nutzen SOLL, und dass der doppelte Unterstrick die Methode bzw Variable tatsächlich private macht....
Nein, ein führender doppelter Unterstrich verwurstet den Namen des Bezeichners nur (name mangling). In PEP-8 und im Tutorial zum Thema Klassen steht etwas dazu. Es verhindert nicht, dass trotzdem ein Zugriff auf die Daten möglich ist.
BlackJack

@elactic: „Logische“ Zeilen enden erst wenn alle Klammern geschlossen sind. Dabei zählen alle Arten von Klammern, also '()', '[]', und '{}'. Solange also noch offene Klammern existieren, kann man Zeilenumbrüche einfügen. Dann gibt es noch '\' am Zeilenende um eine logische Zeile in der nächsten „physikalischen“ Zeile fort zu setzen. Das versuche ich zu vermeiden und setze da lieber einen Ausdruck in ansonsten überflüssige Klammern. Das ist aber eine Geschmacksfrage.

Also wenn das eine Vorgabe der Uni war, dann sind zu wenig Kommentare enthalten. ;-) Mal ernsthaft: Ich glaube auch dann hätte ich etwas ausführlicher über einem grösseren Konstrukt kommentiert. Für Uni-Hausaufgaben hatte ich öfter auch mal „literate programming“ betrieben. Da gibt es mit `pylit` ein ganz nettes Tool für Python und reStructuredText. Ein Beispielprojekt von Python-Quelltext mit unverschämt viel Kommentaren findet sich hier:

Python-Datei: http://bj.spline.de/simpledb/simpledb.py
umgewandelt in HTML: http://bj.spline.de/simpledb/simpledb.html
umgewandelt in PDF: http://bj.spline.de/simpledb/simpledb.pdf

Das HTML ist ohne Syntaxhervorhebung für den Python-Quelltext — ich weiss nicht ob das 2007 noch nicht ging, aber heute würde das natürlich mit `pygmentize` eingefärbt. Das PDF hat einfache Syntaxhervorhebung über Schriftstile. Da hatte ich glaube ich ein kleines Skript gehackt, dass die Python-Quelltexte im LaTeX-Quelltext in ``lstlisting``-Umgebungen gesteckt hat.

Natürlich sind Namen auf Modulebene in Funktionen sichtbar. Wie sollte man sonst Module, Klassen, und Funktionen in Funktionen verwenden!? Alles was man an einen Namen binden kann, ist ein Objekt. Und dem Namen ist der Typ des Objekts egal. Also können auch für alle Namen nur die gleichen Sichtbarkeitsregeln gelten, egal ob da nun per ``import`` ein Modul, per ``class`` eine Klasse, per ``def`` eine Funktion, oder per ``=`` irgend ein Objekt, dran gebunden wurde.

Du kannst ab Python 2.6 vor allen anderen Importen oben um Modul ``from __future__ import print_funktion`` schreiben, dann ist `print()` eine Funktion wie in Python 3.x.

Vom Effekt ist die Semaphore in diesem Fall das gleiche wie ein Lock, ja. Mit ``with`` meine ich die ``with``-Anweisung. `Semaphore` und `Lock` implementieren die dazu notwendigen „magischen“ Methoden:

Code: Alles auswählen

lock.aquire()
# do something
lock.release()

# Besser:

with lock:
    # do something

# Entspricht:

lock.aquire()
try:
    # do something
finally:
    lock.release()
Es wird also sichergestellt, dass in jedem Fall die Sperre auch wieder aufgehoben wird. Und es ist sogar kürzer als die unsicherere, erste Variante.
Antworten