loopback-socket: Welcher PORT ?

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
joost
gelöscht
Beiträge: 134
Registriert: Sonntag 29. April 2007, 13:28

Sonntag 29. April 2007, 14:38

Hi,

habe folgendes Problem:

Eine Anwendung (mit gtk) muss einen subprocess starten, um ein Toplevel-Window zu konstruieren, dessen Position und Größe zu 100% kontrollierbar ist - das geht mit gtk innerhalb eines Programms nicht.

Der Unterprozess soll schlichtweg je einen Datensatz und ein Bild anzeigen, synchron zum Browsen einer db-Tabelle. Nun ist es leider so, dass die pipe Popen(...).stdin unter Windows XPpro (Python 2.4.4) einfach nicht zu funktionieren scheint (stdout schon). Ebensowenig ist das Clipboard dafür brauchbar. Also soll ein socket her - socket und select ist ziemlich neu für mich - schöne neue Übung. Und die Kommunikation zwischen den beiden sockets läuft auch schon.

ABER: Dieses Programm wird gleichzeitig auf vielen Arbeitsplätzen in einem Netzwerk laufen. Wie kann ich sicherstellen, dass meine beiden sockets - das in main und das im subprocess - wirklich nur auf dem jeweiligen Arbeitsplatzrechner arbeiten ?

Ein Workaround, klar: Berechne jeweils eine andere Portnummer aus irgendwelchen Eigenschaften der Arbeitsplatzrechner. Aber das ist nur ein Workaround.

Jedenfalls bleiben sie nicht lokal, wenn mit socket.socket('localhost', int) erzeugt - oder ?

Leider habe ich mir gestern einen Port durch Nicht-Schließen eines sockets dichtgemacht - und der ist heute immer noch ' ... already in use' - nach mehren Neustarts des Arbeitsplatzrechners, aber keinem des Netzwerk-Servers hier).

Diese Frage stellt sich für das loopback-socket ganz allgemein. Warum kann idle eigentlich keinen neuen Port auf localhost suchen, wenn durch Testläufe ruiniert ? Kann (und sollte das unbedingt) ja immer noch melden, dass das alte noch zu schließen ist (also ein toter python-Prozess mit dem Taskmanager zu beenden ist).

Hier habe ich irgendetwas überhaupt nicht verstanden. Diese Frage - so einfach und grundsätzlich sie ist - scheint niemand zu stellen (??). Habe schon eine Stunde Google-Trefferlisten zu 'loopback' und weiteren Suchwörtern durchgesehen - nichts ! Immer nur 'localhost' und 127.0.0.1.

Gehen sockets grundsätzlich auf den Netzwerk-Router ? Was wäre denn dann mit standalone-Rechnern ? Selbstverständlich haben auch die loopback-sockets (->X11).

Antworten auf diese Frage sollten vielen Netzwerk-Anfängern ganz allgemein weiterhelfen können. Aber bitte bitte keine Antwort der Sorte: Installiere ActivePython (oder auch nur Python2.5). Das Problem muss auch so lösbar sein.

Grüße, Joost
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Sonntag 29. April 2007, 17:43

Normalerweise wird "localhost" aufgeloest als 127.0.0.1. Das wiederum sollte im Normallfall die Adresse des loopback-Interfaces sein. D.h. alle Pakte an dieses Interface gehen nicht ans Netz, verlassen die Maschine nicht, es ist nur eine "virtuelle IP-Adresse". Somit es funktioniert es auch auf einem alleinstehenden Rechner. Und wenn du z.B. einen Server-Socket auf localhost aufmachst, solltest du von einem zweiten Rechner aus nicht auf diesen Socket verbinden koennen, denn wie gesagt, der Server-Socket bleibt nur auf seiner Maschine, das Netzwerk bekommt davon ueberhaupt nichts mit.

Das "address already in use" kannst du auf Serverseite umgehen mit:

Code: Alles auswählen

server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Bei mir (Linux) war es aber immer so, dass ich lediglich ein Weilchen warten musste, bis es auch so wieder ging. Was genau mit der "schon verwendeten Addresse" auf sich hat, weiss ich auch garn nicht...

http://en.wikipedia.org/wiki/Loopback
http://en.wikipedia.org/wiki/Loopback_address
lunar

Sonntag 29. April 2007, 18:03

joost hat geschrieben: Jedenfalls bleiben sie nicht lokal, wenn mit socket.socket('localhost', int) erzeugt - oder ?
Damit erzeugst du kein Socket, sondern höchstens eine Ausnahme:

Code: Alles auswählen

portnummer = 10000
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', portnummer))
sock.listen(1)
Jetzt hast du dein Socket, dessen accept Methode dich neue Verbindungen annehmen lässt.
joost
gelöscht
Beiträge: 134
Registriert: Sonntag 29. April 2007, 13:28

Sonntag 29. April 2007, 18:13

Danke !

Hatte aber das Problem inzwischen selbst gelöst - meine entsprechende Nachricht ist aber (sind meine ersten Beiträge) nicht in diesem Thread gelandet (ist auch nicht mehr in der Liste Eigene Beiträge).

Es ist leider Windows - sonst ginge es ja auf diversen einfacheren Wegen (neben Popen(...).stdin ja auch mit einer named pipe oder einem dafür geschaffenen und reservierten gtk.Clipboard). Und dort kann man (und muss wahrscheinlich) eine Loopback nachinstallieren. Das ist z.B. beschrieben auf

http://support.microsoft.com/kb/839013

Danach hat man eine neue Netzwerkverbindung und kann sich mit ipconfig die Adresse holen (bei mir: 169.254.25.129).

Die sockets auf diese Adresse ließen sich nun - schon wieder gingen Programm-Testläufe so schief, dass geöffnete sockets übrigblieben - durch Neustart bereinigen (gut zu wissen). Ich weiß nicht, ob Windows 127.0.0.1 automatisch auf dieses Ding abbildet, und habe da meine Zweifel. Das würde ja im übrigen wohl der Router im Netzwerk tun und der soll von all diesen Aktivitäten gar nicht erst erfahren und den will ich für so etwas natürlich auch nicht benötigen. Die direkte Verwendung kann auf keinen Fall schaden.

Und serverseitig soll eben NICHT eingegriffen werden.

Nochmals Dank, Joost

joost
gelöscht
Beiträge: 134
Registriert: Sonntag 29. April 2007, 13:28

Sonntag 29. April 2007, 18:17

PS,

socket.socket('localhost',int) war natürlich ein Versehen, klar: im Code ist es socket<object>.connect('localhost', int). Schrieb ja auch, dass das schon läuft.

Trotzdem ein Dankeschön, Joost
lunar

Sonntag 29. April 2007, 18:29

joost hat geschrieben:PS,
socket.socket('localhost',int) war natürlich ein Versehen, klar: im Code ist es socket<object>.connect('localhost', int). Schrieb ja auch, dass das schon läuft.
localhost solltest du nie verwenden. Diesen Namen kann man über die hosts Datei umbiegen. Verwende stattdessen einfach einen Leerstring ''. Dadurch kommst du immer zum Loopback-Interface.
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Sonntag 29. April 2007, 18:33

Hi

Ein Leerstring bindet nicht ans Loopback-Interface sondern an alle Interfaces.

Schreib doch einfach sock.bind(('127.0.0.1', portnummer)). Und unter Windows musst du nichts dazu installieren, damit dies funktioniert.

Gruss
joost
gelöscht
Beiträge: 134
Registriert: Sonntag 29. April 2007, 13:28

Sonntag 29. April 2007, 19:22

Dank für all die schnellen Reaktionen !

Aber es ist doch so: Bei etwas so simplem wie der Kommunikation zwischen zwei Toplevel-Fenstern sollte ganz sichergestellt sein, dass kein Bit den Arbeitsplatzrechner verlässt. Auch aus Gründen der Performance: Das Fenster des Subprozesses soll ja möglichst in Echthzeit den Bewegungen des Cursors in einer Datenbank-Tabelle folgen.

Zum Unterschied zwischen '' und 'localhost' aus

http://www.pug.org/index.php/Xen-Installation :

# Address xend should listen on for HTTP connections.
# Specifying 'localhost' prevents remote connections.
# Specifying the empty string '' allows all connections.
(xend-address 'localhost')

Ähnliches gilt auch für Pythons sockets - finde die Referenz dafür auf die Schnelle nicht wieder. Es sollte also im Gegenteil immer dann 'localhost' statt '' verwendet werden, wenn man im lokalen Netzwerk bleiben will.

Und zu 127.0.0.1 aus der RFC 3330 (gerade eben herausgesucht):

127.0.0.0/8 - This block is assigned for use as the Internet host
loopback address. A datagram sent by a higher level protocol to an
address anywhere within this block should loop back inside the host.
This is ordinarily implemented using only 127.0.0.1/32 for loopback,
but no addresses within this block should ever appear on any network
anywhere.

Ok, dann verstehe ich aber wirklich nicht, warum mein fehlerhaft nicht geschlossenes Socket verschiedene Neustarts meines Arbeitsplatzrechners überlebt hat. Die Sockets auf 169.254.25.129 tun dies auf alle Fälle nicht.

Noch ein PPS zum Versehen (für Drittleser), ganz korrekt: socket<object>.connect(('localhost', int)) - (nimmt ein 2-Tupel, nicht 2 Argumente).

Grüße, Joost
joost
gelöscht
Beiträge: 134
Registriert: Sonntag 29. April 2007, 13:28

Montag 30. April 2007, 20:34

Zum vorläufigen Abschluss:

rayo und rebekka hatten Recht, man kann (und sollte wegen Portabilität) wohl 127.0.0.[0-8] oder 'localhost' wählen. Denn inzwischen sind mir auch mit der nachinstallierten MS-Loopback verstopfte Ports untergekommen, die ein Neustart (Neuanmeldung genügte übrigens zeitweise auch) nicht wegbekam. Und ich glaube immer noch, dass das daran liegt, das das (lokale) Netzwerk diese nicht geschlossenen sockets erhält - kann natürlich auch ganz was anderes sein, eine Fehlfunktion der Firewall z.B. , die gar nichts mit den sockets an sich, sondern nur etwas mit den Adressen zu tun hat.

Aber was soll dieses Ding Netzwerkverbindung '169.254.25.129' eigentlich ? Warum hat sich Microsoft die Mühe damit gemacht ? (Dies bitte nicht als Frage, die eine Antwort sucht, mißverstehen).
joost
gelöscht
Beiträge: 134
Registriert: Sonntag 29. April 2007, 13:28

Mittwoch 2. Mai 2007, 16:37

Ach, ja - ist mir inzwischen aufgefallen. Wenn man schon Windows-spezifisch dazuinstalliert, dann doch lieber die win32-Extensions von ActiveState. Und nicht einmal 127.0.0.1 verwenden. Denn dann wird subprocess.stdin wahrscheinlich funktionieren, womit der eigentliche Code 98pro portabel bleibt (denn dass das unter Unix-Derivaten von selbst läuft, davon ist ja wohl auszugehen). Damit ist dieser ganze aufwändige workaround dann erledigt. Ich denke, das mach ich.

War aber lehrreich, client und server mal auf dem eigenen Rechner zusammenarbeiten zu sehen. Das ist ja sicher der Weg, auf dem man Internet-Serveranwendungen testet, und die muss ich als nächstes programmieren. Muss noch viel über Netzwerke lernen.
___________________
Schlechte Software ist schlimmer als keine Software
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Mittwoch 2. Mai 2007, 18:22

joost hat geschrieben:Aber was soll dieses Ding Netzwerkverbindung '169.254.25.129' eigentlich ? Warum hat sich Microsoft die Mühe damit gemacht ? (Dies bitte nicht als Frage, die eine Antwort sucht, mißverstehen).
Zeroconf, [strike]RFC 3330[/strike]

Ich verstehe deine Frage, die angeblich keine ist, wohl irgendwie nicht.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 2. Mai 2007, 18:36

Y0Gi hat geschrieben:Ich verstehe deine Frage, die angeblich keine ist, wohl irgendwie nicht.
Vielleicht ist joost das Wort "rhetorisch" nicht eingefallen. Oder er will uns etwas mitteilen, was ich aber auch nicht so ganz verstehe.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
lunar

Mittwoch 2. Mai 2007, 18:41

rayo hat geschrieben:Ein Leerstring bindet nicht ans Loopback-Interface sondern an alle Interfaces.
Stimmt, mein Fehler. :oops:
Nächstes mal lese ich die Doku und verlasse mich nicht mehr auf meine Erinnerungen ;) versprochen.
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Mittwoch 2. Mai 2007, 18:50

Hi

Also was ich nicht verstehe, was installierst du denn da auf dem Windows? Windows hat von Haus aus immer ein Loopbackinterface mit der Adresse 127.0.0.1, da musst nix installiert werden.

Wenn du den Post öffnest mit Addr '127.0.0.1' und einem beliebigen Port und dann wieder richtig schliesst, gibt es keine Probleme mit Port already in use und es werden auch sicher keine Daten über das Netzwerk gebunden. Mit einem Neustart sind sicher alle von dir belegten Ports wieder frei (vielleicht benutzt eine andere Software den Port den du möchtest)

Gruss
joost
gelöscht
Beiträge: 134
Registriert: Sonntag 29. April 2007, 13:28

Donnerstag 3. Mai 2007, 14:07

Das ist es ja: Windows bietet ein sogenanntes Loopback-Netzwerkfeature an, das ist offenbar in jedem XP enthalten und wird einfach über die Systemsteuerung->Netzwerkverbindungen->Neue_Verbindung_erstellen installiert. Das meinte ich mit 169.254.25.129 - diese Adresse bekam das Ding bei mir. Was um Himmels willen soll das ? Ist die Implementierung von 127.0.0.1 (denn die Konformität zur oben zitierten FRC 3330 muss ja in den Netzwerktreibern des lokalen Rechners implementiert sein) nicht in Ordnung ? Diese Frage war und ist nicht völlig rhetorisch, eigentlich vermute ich, dass unter unseren 7000 Usern schon einige sind, die etwas über diesesdevice wissen. Ich will und wollte aber auf keinen Fall, dass irgendjemand sich mit einer Antwort darauf echte Mühe macht.

Und @rayo:
Wenn du den Post öffnest mit Addr '127.0.0.1' und einem beliebigen Port und dann wieder richtig schliesst, gibt es keine Probleme mit Port already in use und es werden auch sicher keine Daten über das Netzwerk gebunden. Mit einem Neustart sind sicher alle von dir belegten Ports wieder frei (vielleicht benutzt eine andere Software den Port den du möchtest)
- genau das war ja, wie beschrieben, eben nicht so. Zuletzt bekam ich sogar auf vielen Ports nur noch 'Connection refused' (was, wenn sie es ist, die Firewall für 127.0.0.1 imho niemals dürfte).

Habe das zugrundeliegende Problem aber - nach Tagen des Herumprobierens - jetzt endlich mit subprocess.stdin geschafft. Ein wichtiger Punkt hier (steht zwar auch an anderen Stellen in diesem Forum, kann aber gar nicht oft genug gesagt werden): sys.stdin ist unter idle generell unbrauchbar, nicht nur für subprocess.

Das Objekt, das die idle sys.stdin offenbar zuweist, hat keine fileno(), keine read() und wohl überhaupt keine fd-Methoden. Schlimm, dass das nicht an prominenter Stelle in der Doku auftaucht.

Allerdings habe ich es auch nicht mit gobject.io_add_watch(sys.stdin, ... ) geschafft, das scheint auch nicht zu funktionieren.
_______________
never use sys.stdin with idle.pyw
Antworten