Pings und Threads

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Gremlin
User
Beiträge: 166
Registriert: Freitag 28. Mai 2010, 23:49

Hallo,

Ich möchte eine variierende Anzahl IPs anpingen. Das mache ich, damit es nicht zu lange dauert, für jede IP in einem separaten Thread. Selbstverständlich mit einem Timeout:

Code: Alles auswählen

def query(ip_list, timeout):
    if timeout is None or timeout < 1:
        timeout = 1
    print timeout
    start = time.time()
    thread_list = []
    for ip in ip_list:
        # Eigene Klasse, aber fast identisch im Vergleich zum Original
        t = NewThread(fire=True, target=ping.do_one, args=(ip))
        thread_list.append(t)
    for thread in thread_list:
        while thread.is_alive():
            time.sleep(0.01)
        res = thread.get_return_value()
        if res is not None:
            print res
    print time.time() - start, 'sek hats gedauert'
Mein Problem:
Das Ergebnis enthält Pings die weit über dem Timeout liegen:
0.05
0.612943544547
0.613242287217
0.613124402899
0.612961207996
0.613132082659
0.612970423708
0.612978487456
0.613151666047
0.612985783228
...
1.07449290544
1.07528276877
1.07451248883
1.07530811198
...
0.38534578888
0.385557366272
0.385355004592
0.385566197997
5.04199981689 sek hats gedauert
Mein Lösungsansatz:
Datentypen überprüfen, Formatierungen prüfen, etc. Hatte bisher aber keinen Erfolg.
Dann hab ich mir das ping-modul mal näher angesehen (Auch wenn ich da nicht 100% durchsteige..):

Code: Alles auswählen

def do_one(dest_addr, timeout):
    """
    Returns either the delay (in seconds) or none on timeout.
    """
    icmp = socket.getprotobyname("icmp")
    try:
        my_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
    except socket.error, (errno, msg):
        if errno == 1:
            # Operation not permitted
            msg = msg + (
                " - Note that ICMP messages can only be sent from processes"
                " running as root."
            )
            raise socket.error(msg)
        raise # raise the original error

    my_ID = os.getpid() & 0xFFFF

    send_one_ping(my_socket, dest_addr, my_ID)
    delay = receive_one_ping(my_socket, my_ID, timeout)

    my_socket.close()
    return delay

def receive_one_ping(my_socket, ID, timeout):
    """
    receive the ping from the socket.
    """
    timeLeft = timeout
    while True:
        startedSelect = time.clock()
        whatReady = select.select([my_socket], [], [], timeLeft)
        howLongInSelect = (time.clock() - startedSelect)
        if whatReady[0] == []: # Timeout
            return

        timeReceived = time.clock()
        recPacket, addr = my_socket.recvfrom(1024)
        icmpHeader = recPacket[20:28]
        type, code, checksum, packetID, sequence = struct.unpack(
            "bbHHh", icmpHeader
        )
        if packetID == ID:
            bytesInDouble = struct.calcsize("d")
            timeSent = struct.unpack("d", recPacket[28:28 + bytesInDouble])[0]
            return timeReceived - timeSent

        timeLeft = timeLeft - howLongInSelect
        if timeLeft <= 0:
            return
Kann es sein, dass es ein Problem darstellt dass ich Threads verwende? Ich komme darauf, weil es ohne wie erwartet funktioniert und weil:

Code: Alles auswählen

...
my_ID = os.getpid() & 0xFFFF
....
if packetID == ID:
Falls ja, was muss ich ändern damit es mit Threads funktioniert?
Oder hat es mit etwas ganz anderem zu tun, was ich hier übersehe?

Ich habe bis jetzt noch nichts weiter ausprobiert, um das mit den Threads zu untermauern, denn wie schon erwähnt: Ich versteh das, was das ping-modul da macht noch nicht so wirklich und denke mir, ich hab hier evtl. mehr Glück, bei Leuten die schon Erfahrung damit haben. :)
Gremlin
User
Beiträge: 166
Registriert: Freitag 28. Mai 2010, 23:49

Mir fällt grad auf, dass ich bei meinem Beispiel oben das Timeout nicht an den Thread übergebe. Natürlich ist das nur ein Fehler im Beispiel. :roll:
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Vielleicht ist es auch einfacher nmap per subprocess zu starten und beispielsweise ein ganzen sub netz zu scannen.
z.B.:

Code: Alles auswählen

nmap -e eth0 -sP 10.0.0.0/24
Vorteil ist, das es viel schneller geht und auch ohne root rechte funktioniert. Nachteil ist, nmap ist i.d.R. nicht installiert und du musst die Ausgaben auswerten, was aber recht einfach sein sollte...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Gremlin
User
Beiträge: 166
Registriert: Freitag 28. Mai 2010, 23:49

Ich möchte es allerdings so gut wie möglich vermeiden, auf externe Programme zuzugreifen. Jedenfalls solange es anders geht.
Ich versuch jetzt einfach mal das ping-modul so abzuändern, dass es nicht mehr von der PID abhängt. Obs was bringt weiß ich allerdings nicht, aber hier wird auch keine PID für die Identifizierung des Paketes verwendet.
Gremlin
User
Beiträge: 166
Registriert: Freitag 28. Mai 2010, 23:49

Also, nur an der PID liegts nicht. Scheint zwar auch mit dem Problem im Zusammenhang zu stehen, aber bevor ich mir darüber den Kopf zerbreche muss ich ihn mir an etwas anderem weichknüppeln. Ich bin inzwischen soweit, dass es am Socket selbst liegt, der pro Thread erstellt wird.

Kann es sein dass sich verschiedene Sockets ein und den selben Buffer teilen? Oder besser, gibt es eine maximale Zahl an Sockets die von einem Prozess in Anspruch genommen werden können, und somit Duplikate entstehen? Ich komme darauf, weil ich statt "select", das timeout vom socket-modul genommen habe und nun jedesmal ein Timeout erhalte wenn ich mit socket.recvfrom(1024) die Daten abfrage, egal bei welcher IP. Erst wenn ich das Timeout höher einstelle bekomme ich ein paar Ergebnisse (die natürlich falsch sind, aber das ist ja jetzt nicht mehr das Hauptproblem..). Also scheint mehr im Buffer zu sein als ich erwarte, oder nicht?

Falls es so ist wie ich denke, hat dann jemand einen Tipp für mich wie ich das kompensiere? Hab schon was von asyncore gelesen, aber ich konnte nicht wirklich aus der Doku rauslesen ob es das ist was "ich" brauche.

Edit:
Gut, Sockets werden scheinbar nicht limitiert, hatte gerade 10001 aktiv davon einer in einem separaten Thread mit einzigartiger file descriptor id.
Ist denn die file descriptor id mit dem Buffer gleichzusetzen?

Ach und weil mir das grade auffällt: Es geht um Windows und Python 2.7^^
Gremlin
User
Beiträge: 166
Registriert: Freitag 28. Mai 2010, 23:49

Dreifachposts gehören zwar nicht zu meiner üblichen "Manier" aber stört wohl sowieso niemanden.
Für den Fall dass jemand über die Suchfunktion hier landet oder was weiß ich:

ping.py (jetzt auch mit asynchronen sockets und linux kompatiblität)
Antworten