Problem: Große Anzahl von IP-Adressen verwalten!

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
elLobo

Hallo!

Ich möchte gerne in Python eine große Anzahl von IP-Adressen und zugehörigen Port-Nummern verwalten. Ich bekomme Ranges von IP-Adressen und Port-Nummern und will dann aus diesen Tupel bilden. Also <IP:Port> eben. Jedes dieser Tupel darf aber nur einmal benutzt werden.

Irgendwie ist dieses Problem nicht so trivial wie es scheint... die Datenmengen können nämlich sehr groß werden... von den Port-Nummern gibt es ja schon alleine 65 Tausend...

Welche Datenstruktur könnte ich dafür in Python benutzen... ?

Stehe da im Moment voll auf dem Schlauch... über jede Anregung wäre ich dankbar!

mfg elLobo
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dazu nimmst du am besten ein Set (= Menge), dadurch wird garantiert, dass es jede Tupel nur einmal im Set gibt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Gast

Leonidas hat geschrieben:Dazu nimmst du am besten ein Set (= Menge), dadurch wird garantiert, dass es jede Tupel nur einmal im Set gibt.
Ahh... Set... kannte ich noch gar nicht... danke!

Aber damit habe ich doch auch das Problem, wenn ich zuviele IPs und Ports habe, die Datenmengen sehr groß werden.... hat jemand Erfahrungswerte, bis zu welcher Größe ich in Python z.B. eine Liste mit Integerwerten füllen kann, bis mir alles abschmiert?

mfg elLobo
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Solange dir das Virtual Memory mitspilet. Auf 32-Bit Systemen hat jeder Prozess 2 GB Speicher zur verfügung, wenn du drüber kommst: schlecht.

Allerdings rate ich dir von Listen ab, nimm dafür eben besser Sets.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Oder gleich direkt eine Datenbank! Vielleicht SQLite...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
elLobo

Leonidas hat geschrieben:Solange dir das Virtual Memory mitspilet. Auf 32-Bit Systemen hat jeder Prozess 2 GB Speicher zur verfügung, wenn du drüber kommst: schlecht.

Allerdings rate ich dir von Listen ab, nimm dafür eben besser Sets.
Worst-Case: Klasse-A-Netz -> 16.774.214 Adressen x 65.536 Port-Nummern = ca. 1 Billion Tupel. :shock:

Je Tupel 8 Byte Speicherbedarf -> ca. 8 Tebibyte :shock:

Selbst ein Klasse-B-Netz würde den Rahmen von 2Gb sprengen...

Habe noch nie so große Datenmengen verwalten müssen...

mfg elLobo
Gast

jens hat geschrieben:Oder gleich direkt eine Datenbank! Vielleicht SQLite...
Hmmm.... werde ich mir anschauen... aber eigentlich wollte ich auf eine Datenbank verzichten... Danke für den Tip!

mfg elLobo
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

http://sqlite.org
Supports databases up to 2 terabytes (241 bytes) in size.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

elLobo hat geschrieben: Irgendwie ist dieses Problem nicht so trivial wie es scheint... die Datenmengen können nämlich sehr groß werden... von den Port-Nummern gibt es ja schon alleine 65 Tausend...
Welche Datenstruktur könnte ich dafür in Python benutzen... ?
Hi elLobo!

Du könntest "shelve" verwenden. Shelve verhält sich wie ein Dictionary, speichert die Daten aber in ein File-Objekt ab. Das Lesen von einzelnen Werten aus diesem Objekt ist ziemlich schnell. Ich habe das Ganze mit 1 Mio. Datensätze unter Linux ausprobiert.

Hier ein Beispiel:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import shelve

# Schreiben
sh = shelve.open("filename", protocol = 2)
sh["Vorname"] = "Nudelaug"
sh["Nachname"] = "Thompson"
sh.close()

# Lesen
sh = shelve.open("filename", protocol = 2)
print sh["Vorname"]
print sh["Nachname"]
sh.close()
Beispiel zum Testen:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
"""
******************************************************************************
* Description:  Shelve-Test
* Help:         http://www.python.org/doc/current/lib/module-shelve.html
******************************************************************************
"""

import os
import os.path
import shelve

FILENAME = "shelvefile"
MAX = 200000
PROTOCOL = 2


#----------------------------------------------------------------------
def fill_shelve(key = None, value = None):
    """
    Befüllt das Objekt mit Daten.
    """
    
    sh = shelve.open(FILENAME, protocol = PROTOCOL)
    
    print "fill - begin"
    
    if key is None:
        for i in range(MAX):
            sh[str(i)] = "Eintrag Nummer %s" % i
            if i % 1000 == 0:
                print "fill - %s" % i
    else:
        sh[key] = value
        
    sh.close()
    
    print "fill - end"
    

#----------------------------------------------------------------------
def read_shelve(direction = "asc", additional_keys = None):
    """
    Liest ein paar Daten aus dem Shelve aus.
    """
    
    sh = shelve.open(FILENAME, protocol = PROTOCOL)

    print "read - begin"
    
    if direction == "asc":
        for i in range(0, MAX, 1500):
            print "read - %s = %s" % (i, sh[str(i)])
    else:
        for i in range(MAX - 1, 0, -1500):
            print "read - %s = %s" % (i, sh[str(i)])
            
    if additional_keys:
        for key in additional_keys:
            print "read - %s = %s" % (key, sh[key])
    
    sh.close()
    
    print "read - end"
    
    
#----------------------------------------------------------------------
def main():
    """
    Hauptprozedur
    """
    
    if not(os.path.isfile(FILENAME)):
        fill_shelve()

    fill_shelve("Vorname", "Nudelaug")
    fill_shelve("Nachname", "Thompson")
    
    read_shelve("asc")
    read_shelve(
        "desc", 
        (
            "Vorname", 
            "Nachname"
        )
    )


#----------------------------------------------------------------------
if __name__ == "__main__":
    main()
Hier findest du Hilfe zu shelve

mfg
Gerold
:-)

Edit: Protokoll auf das schnellere Binary-Protokoll gesetzt.
Edit2: Um Shelve eine bessere Chance zu geben, habe ich ein Kurzbeispiel eingefügt.
Zuletzt geändert von gerold am Dienstag 3. Januar 2006, 21:51, insgesamt 3-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

gerold hat geschrieben:Du könntest "shelve" verwenden.
Dabei würde ich aber das beachten: http://www.python.org/doc/current/lib/node64.html

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

jens hat geschrieben:Dabei würde ich aber das beachten: http://www.python.org/doc/current/lib/node64.html
Hi Jens!

Danke, habe ich ins Beispiel eingebaut.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Für so große Datensätze und für so einfachen aufbau würde ich ein Array nehmen. Die Dinger nutzen den Speicher besser, da keine Referenzen und Objekte abgelegt werden, sondern wirklich nur die Werte.

Code: Alles auswählen

>>> from array import array
>>> iplist = []
>>> iplist.append(array("B", [255, 255, 255, 255]))
>>> iplist.append(array("B", [0, 0, 0, 0]))
>>> iplist
[array('B', [255, 255, 255, 255]), array('B', [0, 0, 0, 0])]
TUFKAB – the user formerly known as blackbird
BlackJack

Bei so einer grossen Datenmenge sind auch Arrays nix. Die müssten dann alle in den Speicher passen. Und wenn man das Array dynamisch vergrössert, muss unter Umständen sogar 3x soviel Speicher vorhanden sein, damit das klappt.

elLobo hat noch nicht geschrieben, was er mit den Daten eigentlich machen will. Wenn man zum Beispiel als Anforderung hat, alle Portnummern zu einer gegebenen IP herauszufinden, dann ist das lineare Suchen in Arrays oder Listen von diesen Ausmassen *äusserst* ungünstig.

Ich würde mich dem Vorschlag mit der Datenbank anschliessen. Die sind für solche Datenmengen gedacht.
elLobo

BlackJack hat geschrieben: elLobo hat noch nicht geschrieben, was er mit den Daten eigentlich machen will. Wenn man zum Beispiel als Anforderung hat, alle Portnummern zu einer gegebenen IP herauszufinden, dann ist das lineare Suchen in Arrays oder Listen von diesen Ausmassen *äusserst* ungünstig.
I
Es sollen aus einer Liste von gültigen IPs und Ports entsprechende Tupel gebildet werden und diese einem "anderem System" zur Verfügung gestellt werden.

Ich denke man kann an die Sache aus zwei Richtungen ran gehen:

1. Ich bilde aus allen gültigen IPs und Ports ein Tupel und kontrolliere, ob dieses schon benutzt wurde, falls nicht, wird es in eine "Blacklist" eingetragen. Der Vorteil hierbei wäre, dass die Datenmenge recht lansgam steigt, aber mit der Zeit es immer schwieriger wird, ein noch nicht benutztes Tupel zu finden, also steigt auch der Aufwand...

2. Ich erstelle gleich von Beginn an, eine komplette Liste mit allen gültigen Tupeln und lösche dann nach und nach alle benutzten raus. Nachteil, ich brauche verdammt viel Speicherplatz...

Welche Version scheint sinnvoller?

Danke soweit für die Tips... werde mir das alles anschauen...

mfg elLobo
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

elLobo hat geschrieben:Es sollen aus einer Liste von gültigen IPs und Ports entsprechende Tupel gebildet werden und diese einem "anderem System" zur Verfügung gestellt werden.
Hi elLobo!

Du schreibst nur, wie du an die Sache ran gehen würdest, aber nicht, wofür du es wirklich brauchst. So können wir dir keinen besseren Vorschlag geben.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
elLobo

gerold hat geschrieben:
elLobo hat geschrieben:Es sollen aus einer Liste von gültigen IPs und Ports entsprechende Tupel gebildet werden und diese einem "anderem System" zur Verfügung gestellt werden.
Hi elLobo!

Du schreibst nur, wie du an die Sache ran gehen würdest, aber nicht, wofür du es wirklich brauchst. So können wir dir keinen besseren Vorschlag geben.

mfg
Gerold
:-)
Naja... das steckt nix tieferes hinter... letzendes soll halt ein bestehendes Programm um die Fähigkiet erweitert werden, wie oben beschrieben, IP-Adressen zu verwalten...

Eure Tips schaue ich mir morgen an und wenn ich dann noch Fragen habe, schreib ich nochmal.... was am Ende daraus geworden ist, erfahrt ihr dann auch noch. :wink:

mfg elLobo
BlackJack

Die Frage bleibt: Warum? Was ist der Sinn und Zweck? Wie werden die Adressen "erzeugt"? In welcher Reihenfolge? Werden überhaupt alle Möglichkeiten erzeugt? Was heisst einem anderem System zur Verfügung stellen?

Das jemand wirklich alle IP-Adressen + Portnummern einfach so als Daten haben möchte klingt zumindest komisch.

Ansonsten würde ich das ganze "Klassenweise" als Bitset auf der Platte verwalten. Für ein einzelnes Klasse A Netz wären das "nur" ca. 128 Gigabyte. Platten in der Grössenordnung sind ja nicht mehr sooo exotisch. Wenn Du 256 Stück davon einbaust, dann kannst Du das gesamte Netz erfassen. Naja IPv4 zumindest. :twisted:
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

BlackJack hat geschrieben:Naja IPv4 zumindest. :twisted:
Das hast du aber schön gesagt. :P
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

elLobo hat geschrieben:1. Ich bilde aus allen gültigen IPs und Ports ein Tupel und kontrolliere, ob dieses schon benutzt wurde, falls nicht, wird es in eine "Blacklist" eingetragen. Der Vorteil hierbei wäre, dass die Datenmenge recht lansgam steigt, aber mit der Zeit es immer schwieriger wird, ein noch nicht benutztes Tupel zu finden, also steigt auch der Aufwand...
Mir ist auch unklar, was du eigentlich machen willst... Aber generell finde ich diesen Ansatz schon ganz gut.
Vielleicht solltest du allerdings jede IP mit einem timestamp versehen. Wenn du eine echte Datenbank benutzt ist es eine Kleinigkeit automatisch veraltete IP-Adressen zu löschen. Ich meine IP-Adressen sind in der Regel relativ flüchtig.
Außerdem kannst du dir die letzte Freie IP-Adresse seperat festhalten und von da an, die nächste freie Suchen... Macht ja keinen Sinn ständig von Null an zu fangen ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Hi OP!

Ich hab für mein Projekt PyFWBuilder eine Set-Klasse geschrieben die für Integers gedacht ist, und ich hab auch eine kleine Erweiterung für IP-Ranges oben drauf. Das Ding ist unter:

http://aspn.activestate.com/ASPN/Cookbo ... ipe/466298

und

http://aspn.activestate.com/ASPN/Cookbo ... ipe/466286

zu finden. Was genau Du willst ist denke ich nicht implementiert, aber wenn Du effizient port/ip paare speichern willst ist es sicherlich ein einfaches die IP4Range-Klasse soweit zu ändern dass sie noch <ip>:<port> akzeptiert. Daraus erstellst Du dann eine Zahl in der Form:

<port><ip>

Zum Beispiel (in Hex-Notation):

172.22.162.250:50

würde zu

0x0032ac16a2fa

Diese Zahl speicherst Du dann im integer set.

Du ein ganzes Subnet mit einem Port hast würde dass zum Beispiel für:

172.22.162.0/24:50

folgende Zahlen bedeuten:

0x0032ac16a200 - 0x0032ac16a2ff

Das lässt sich natürlich sehr effizient in einem Integer set speichern, und es ist sogar halbwegs sinnvoll darüber Mengen-Relationen zu bilden. Und: die Klasse hat ein einfaches iterator-Protokoll in IntSet bereits vorimplementiert. Du könntest also einfach über das set iterieren, und so alle Hosts die zu fragen sind rauskriegen.

Wenn noch Fragen sind, frag!

--- Heiko.
Antworten