ack schrieb:
> Was bedeutet dieser TIME_WAIT state? Ich nehme an, dass dieser die
> Ursache für das Versanden des erneuten Verbindungsaufbaus ist, also dass
> die Pakete weder an einem listening Socket ankommen, noch abgelehnt
> werden, sondern einfach leise ignoriert werden.
> Das scheint mir auch ein generelles Linux/TCP Konzept zu sein und nichts
> mit Python zu tun zu haben.
Mit linux hat dies nichts zutun. TCP verbindungen können sich in
verschiedenen Zuständen befinden, im rfc 793 auf Seite 23 gibt's dazu
ein schönes diagramm: https://tools.ietf.org/html/rfc793#page-23
Grundsätzlich müssen bem Verbindungsaufbau zuerst beide
Verbindungspartner dem anderen ein SYN flag senden, und dessen Empfang
mit einem ACK flag bestätigen. Es spielt keine rolle, wer damit anfängt
oder ob beide gleichzeitig ein SYN senden, es müssen einfach nur beide
in einem Zustand sein in welchem sie ein SYN erwarten, und die quell und
ziel ports, etc. der Packete müssen stimmen. Es ist jedoch üblich das
einer im listening state auf Verbindungen wartet und der andere das
erste SYN sendet und dann im syn sent state auf ein SYN und ein ACK
wartet. Danach ist die verbindung aufgebaut und im ESTABLISHED state.
Falls jedoch ein Verbindungspartner kein SYN erwartet, aber eines
erhält, wird ein RST gesendet um den verbindungsaufbau abzulehnen. Wenn
man eine Verbindung abbricht wird ein RST gesendet, das sollte man
vermeiden weil dann unklar ist ob alle gesendeten Daten auch angekommen
sind. Beim schliessen der Verbindung wird ein FIN gesendet. Beide
Verbindungspartner müssen ein FIN senden und dessen empfang mit einem
ACK bestätigen, die Verbindung zu schliessen. Wenn man ein FIN sendet,
muss der Verbindungspartner das nicht unbedingt auch tun, man sagt damit
nur, dass man selbst keine Daten mehr senden wird. Der
Verbindungspartner kann dann weiterhin Daten senden.
Der TIME_WAIT state existiert, damit zwischen zwei Rechnern in einem
gewissen Zeitraum nach dem schliessen einer Verbindung nicht erneut eine
Verbindung mit dem selben source und destination port, etc. geöffnet
wird, und verspätete Packete kein RST auslösen. Dies verhindert auch,
dass verspätete Packete der alten Verbindung zu problemen führen. Dies
stellt hier jedoch definitiv nicht das Problem dar.
Wenn du mit netcat auf eine Verbindung wartest, dann ist die Verbindung
im LISTENING state. Dabei wird auf ein SYN gewartet, das an den
richtigen destination port geht, und von einem beliebigen source port
kommt.
Wenn dein Programm die Verbindung initiiert, sendet es ein SYN und ist
dann im syn sent state. Jeder TCP Stack wird dabei den angegebenen
destination port verwenden, aber sofern man den Source port nicht
explizit festlegt diesen zufällig wählen. Deshalb würde beim erneuten
Verbindungsaufbau ein anderer source port gewählt, womit die Kombination
aus source und destination port nicht der Verbindung im TIME_WAIT
zustand von vorher zugeordnet werden kann, womit dies nicht das Problem
sein kann.
Man könnte jetzt mit Wireshark nachsehen, was los ist, aber eigentlich
macht das ganze nur sinn, wenn nicht versucht wird eine neue Verbindung
aufzubauen.
Wenn ich die API geschrieben hätte, hätte ich nicht vorgesehen, dass
jemand versucht eine neue Verbindung mit einem alten Verbindungsobjekt
herzustellen. Das ist nur eine Vermutung, aber versuche mal ein neues zu
erstellen. Ungetestet:
1 | import sys
|
2 | from PyQt4 import QtCore, QtGui, QtNetwork
|
3 |
|
4 | class Client():
|
5 | def __init__(self):
|
6 | self.tcpSocket = None
|
7 |
|
8 | def reconnect(self):
|
9 | if self.tcpSocket is not None:
|
10 | self.tcpSocket.abort()
|
11 | self.connect()
|
12 |
|
13 | def connect(self):
|
14 | self.tcpSocket = QtNetwork.QTcpSocket()
|
15 | self.tcpSocket.error.connect(self.displayError)
|
16 | self.tcpSocket.connectToHost("127.0.0.1", 8080)
|
17 |
|
18 | def displayError(self, socketError):
|
19 | print("The following error occurred: %s." % self.tcpSocket.errorString())
|
20 | self.reconnect()
|
21 |
|
22 | if __name__ == '__main__':
|
23 | app = QtGui.QApplication(sys.argv)
|
24 | c = Client()
|
25 | c.connect()
|
26 | sys.exit(app.exec_())
|