
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hallo,
ich versuche gerade für einen Bugreport einen (fast) minimalen Socket Server und Client zu bauen. Der Server soll einen Request bearbeiten und sich dann beenden. Der Client liest nur vom Server.
Nachdem Client und Server ihre Arbeit getan haben, hängt aber noch eine Socket-Verbindung in Status TIME_WAIT herum. Ich finde nicht, wo der Haken ist. Nur, wenn ich das file.read() im Client weg lasse, wird der Socket sauber geschlossen.
Was mache ich falsch?
...8<-------- Server ------- import SocketServer import sys
MyRequestHandler = SocketServer.StreamRequestHandler
if sys.argv[1:]: port = int(sys.argv[1]) else: port = 8000 server_address = ('', port)
d = SocketServer.TCPServer(server_address, MyRequestHandler) print "Serving on %s port %s ..." % d.socket.getsockname()
# handle one request only d.handle_request() print d.socket d.server_close() ...8<-----------------------
...8<-------- Client ------- import socket import sys
if sys.argv[1:]: port = int(sys.argv[1]) else: port = 8000 server_address = ('localhost', port)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(server_address)
file = sock.makefile() # wenn man die nächste Zeile weg laesst, schliesst der socket sauber print file.read(), file.close() sock.close() ...8<-----------------------
- -- Schönen Gruß - Regards Hartmut Goebel
Goebel Consult - Wir machen IT sicher - www.goebel-consult.de

Hallo Hartmut,
Hartmut Goebel schrieb:
Was mache ich falsch?
nischt. Klingt nach:
http://www.google.de/search?q=python+setsockopt+reuse
Einfach entsprechend die Option via setsockopt setzen. Möglich, dass der SocketServer ein Attribut "reuse_address" o.ä. bietet.
HTH, Florian

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hallo Florian,
Hartmut Goebel schrieb:
Was mache ich falsch?
nischt. Klingt nach:
Es kommt mir aber sehr komisch vor, dass die TCP-Verbindung nicht sauber abgebaut wird. Irgendwas scheint mir da doch faul.
- -- Schönen Gruß - Regards Hartmut Goebel
Goebel Consult - Wir machen IT sicher - www.goebel-consult.de

Hallo Hartmut,
Hartmut Goebel schrieb:
Hartmut Goebel schrieb:
Was mache ich falsch?
nischt. Klingt nach:
Es kommt mir aber sehr komisch vor, dass die TCP-Verbindung nicht sauber abgebaut wird. Irgendwas scheint mir da doch faul.
Ne, AFAIK ist TIME_WAIT nach geschlossenem Socket eine Zeitsperre für TCP-Verbindungen, um sicherzustellen, dass die Verbindungen auch wirklich korrekt geschlossen wurden und dementsprechend dafür genug Zeit hatten (die Sperrzeit liegt bei ein paar Minuten). Wenn keine Verbindungen existierten/existieren, so besteht auch kein Grund für eine Sperrzeit (daher der Effekt, dass das TIME_WAIT erst nach einer Clientaktivität auftritt).
Möchtest du den Port vor der Sperrzeit wieder benutzen, so nutze einfach die REUSE-Option, die du für einen low-level-Socket über die Methode setsockopt aktivieren kannst.
HTH, Florian

Florian Schlachter schrieb:
Ne, AFAIK ist TIME_WAIT nach geschlossenem Socket eine Zeitsperre für TCP-Verbindungen, um sicherzustellen, dass die Verbindungen auch wirklich korrekt geschlossen wurden und dementsprechend dafür genug Zeit hatten (die Sperrzeit liegt bei ein paar Minuten). Wenn keine Verbindungen existierten/existieren, so besteht auch kein Grund für eine Sperrzeit (daher der Effekt, dass das TIME_WAIT erst nach einer Clientaktivität auftritt).
Ergänzend ein paar Zitate aus dem RFC 793[1]:
"TIME-WAIT STATE The only thing that can arrive in this state is a retransmission of the remote FIN. Acknowledge it, and restart the 2 MSL timeout."
sowie
"TIME-WAIT - represents waiting for enough time to pass to be sure the remote TCP received the acknowledgment of its connection termination request."
Gruß Florian

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hallo,
Ups, da ist der Handle doch etwas zu klein ausgefallen. Mit dem der gar nicht tut, gibt es auch keine Probleme. Aber dieser, der ein Paar Zeichen über die Leitung schick, verursacht die Probleme.
class MyRequestHandler(SocketServer.StreamRequestHandler): def handle(self): print >> self.rfile, "Hallo Client"
Herausgefunden ahbe ich noch, dass der Verbindungs-Abbau unvollständig ist:
8000 > 43211 FIN, ACK 43211 > 8000 FIN, ACK 8000 > 43211 ACK
Es fehlt also das ACK für das Beenden der Verbindung ducht den Server.
- -- Schönen Gruß - Regards Hartmut Goebel
Goebel Consult - Wir machen IT sicher - www.goebel-consult.de

Hallo Hartmut,
Am Mittwoch, 14. März 2007 22:50 schrieb Hartmut Goebel:
Herausgefunden ahbe ich noch, dass der Verbindungs-Abbau unvollständig ist:
8000 > 43211 FIN, ACK
der Server bestätigt das vorherige TCP-Paket und setzt FIN, um das Schließen seiner Seite der Verbindung zu verkünden.
43211 > 8000 FIN, ACK
der Client bestätigt das vorherige TCP-Paket und setzt FIN, um das Schließen seiner Seite der Verbindung zu verkünden.
8000 > 43211 ACK
Der Server bestätigt das letzte Paket des Clients. Der Socket befindet sich nun im Status TIME_WAIT, um zu verhindern, dass eine andere Anwendung diesen Socket (genauer TCP-Port 43211) benutzt und eventuell verspätet eintreffende TCP-Pakete der vorherigen Nutzung bekommt. Wenn Du diesen Schutz nicht möchtest, setze SO_REUSEADDR, wie an anderer Stelle bereits vorgeschlagen wurde.
Es fehlt also das ACK für das Beenden der Verbindung ducht den Server.
Es ist alles in Ordnung. Wenn das gezeigte Verhalten nicht richtig wäre, würde das bedeuten, dass der TCP/IP-Stack Deines Betriebssystems kaputt ist, nicht das Python Programm.
Gruß Karsten

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hallo Karsten,
Der Server bestätigt das letzte Paket des Clients. Der Socket befindet sich nun im Status TIME_WAIT, um zu verhindern, dass eine andere Anwendung diesen Socket (genauer TCP-Port 43211) benutzt und eventuell verspätet eintreffende TCP-Pakete der vorherigen Nutzung bekommt.
IC. Und ich dachte, ich kenne mich mit TCP aus :-\
Habe das eben mit natcat nachgestellt (weil ich es nicht glauben wollte ;-) und da ist es genau so. Nur verwendet netcat seit 2002 standardmaäßig SO_REUSEADDR -- wie wohl die meisten Anwendungen --, daher ist das nicht aufgefallen.
Danke
- -- Schönen Gruß - Regards Hartmut Goebel
Goebel Consult - Wir machen IT sicher - www.goebel-consult.de
participants (3)
-
Florian Schlachter
-
Hartmut Goebel
-
Karsten Schulz