Forum: PC-Programmierung TCP - Port hängt, wenn ACK fehlt


von Markus_AC (Gast)


Lesenswert?

Hallo zusammen,

ich weiß nicht, ob das nun ein QT-spezielles Problem ist oder ein 
generelles Netzwerk Problem. In diversen QT-Forum wurde mir bislang 
nicht geholfen.

Ich sitze gerade vor folgendem Problem:
Ich habe ein Applikation unter QT, die eine Client-Server-Kommunikation 
durchführt. Dabei verbindet sich ein Client mit dem Server. Ab dann 
werden Daten in der Form gesendet, dass der Server etwas sendet und der 
Client antwortet.
Ich habe nur das Problem bei einen ungewollten Verbindungsabbruch (z.B. 
durch ziehen des Netzwerkkabels).
Mein Server ist  realisiert durch ein QTcpServer. Sobald sich der Client 
verbindet, mache ich dahin ein QTcpSocket auf (nextPendingConnection()).
Wenn nun Daten zum Client gesendet werden, aber das ACK auf dieses Paket 
nicht erfolgt, geschieht folgendes:
Mein TCP/IP-Stack scheint automatisch Keep-Alive-Messages zu senden. 
Wenn dann mehrmals keine Antwort kam, bekommt mein QTcpSocket mit, dass 
es disconnected wurde. Ein nachfolgender Versuch, die Verbindung zu 
schließen (ein FIN-Packet) schlägt dann auch fehlt.
Fatal an der ganzen Geschichte ist, dass ich den TCP/IP-Port, der hier 
nicht ordentlich geschlossen werden konnte, danach nie wieder benutzen 
kann. Erst nach einem Neustart des Computers geht es wieder.

Hat jemand einen Tipp für mich, was ich versuchen könnte?

von Peter II (Gast)


Lesenswert?

Markus_AC schrieb:
> Fatal an der ganzen Geschichte ist, dass ich den TCP/IP-Port, der hier
> nicht ordentlich geschlossen werden konnte, danach nie wieder benutzen
> kann. Erst nach einem Neustart des Computers geht es wieder.

Es geht doch um einen PC oder? Welchens betriebssystem? Diesen Verhalten 
kann überhaupt nicht sein, weil die sockets einer anwendung zugeordnet 
sind, wenn du die Anwendung zumachst, dann werden auch alles Resourcen 
freigeben die damit verbunden sind - beleibt bestimmt nichts offen.

Was sagt denn Netstat zu diesem Port?

von R. M. (rmax)


Lesenswert?

Versuch es mal mit der Socket-Option SO_REUSEADDR (Details siehe "man 7 
ip"). Wie man die mit Qt setzt, kann ich Dir allerdings nicht sagen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> Diesen Verhalten
> kann überhaupt nicht sein, weil die sockets einer anwendung zugeordnet
> sind, wenn du die Anwendung zumachst, dann werden auch alles Resourcen
> freigeben die damit verbunden sind - beleibt bestimmt nichts offen.

Nein, ein nicht ordentlich geschlossener serverseitiger Port kann
für eine bestimmte Zeit vorerst nicht wieder belegt werden.  Damit
soll verhindert werden, dass beim Wiederherstellen der Verbindung
eventuell noch kursierende Pakete versehentlich einem bereits
gestarteten neuen Serverprozess zugeordnet werden, obwohl sie
eigentlich ein ICMP destination port unreachable generieren müssten,
da sie ja für die nicht ordnungsgemäß beendete Verbindung bestimmt
waren.

Der entsprechende Port sollte dann im netstat als "TIME_WAIT"
markiert sein.  Allerdings ist die Wartezeit endlich (was um die
2 Minuten vielleicht, wenn ich mich recht entsinne), und es sollte
nicht erst eines Neustarts bedürfen.

SO_REUSADDR verhindert diesen TIME_WAIT-Zustand.

von Markus_AC (Gast)


Lesenswert?

Gut, ich werde das mal versuchen.
Ich arbeite übrigens sowohl mit Windows- als auch mit einer 
Linux-Umgebung. Das Verhalten ist bei beiden gleich. Allerdings kommt 
unter der Linux-Umgebung das disconnect nach den Keep-Alive-Messages 
nicht (zumindest nicht so schnell wie unter Windows, da ist es etwa 2 
Min.).

von tcpdump (Gast)


Lesenswert?

Lade mal einen Netzwerktrace hoch.

von Markus_AC (Gast)


Angehängte Dateien:

Lesenswert?

Hier der Auszug aus dem Wireshark, wenn ich das Netzwerkkabel entferne.
Mein Server (192.168.214.251) sendet ein Paket mit Daten der Länge 1, 
das fehlende ACK der Clients (192.168.214.252) wird mit 5 
Keep-Alive-Messages behandelt.
Allerdings kann ich nach fast 400 Sekunden immer noch nicht den Port 
öffnen, obwohl der Default-Wert für TIME_WAIT 240 Sekunden ist. Der 
vorher geöffnete UDP Port funktioniert jedoch.
Leider habe ich bisher keine Möglichkeit gefunden, in QT die 
Socket-Option SO_REUSEADDR zu setzen.
Da es aber auch nach der TIME_WAIT Zeit nicht funktinoiert, muss noch 
etwas anderes im Argen sein...

von Socken (Gast)


Lesenswert?

Markus_AC schrieb:
> Hier der Auszug aus dem Wireshark, wenn ich das Netzwerkkabel entferne.
> Mein Server (192.168.214.251) sendet ein Paket mit Daten der Länge 1,
> das fehlende ACK der Clients (192.168.214.252) wird mit 5
> Keep-Alive-Messages behandelt.
> Allerdings kann ich nach fast 400 Sekunden immer noch nicht den Port
> öffnen, obwohl der Default-Wert für TIME_WAIT 240 Sekunden ist. Der
> vorher geöffnete UDP Port funktioniert jedoch.
> Leider habe ich bisher keine Möglichkeit gefunden, in QT die
> Socket-Option SO_REUSEADDR zu setzen.
> Da es aber auch nach der TIME_WAIT Zeit nicht funktinoiert, muss noch
> etwas anderes im Argen sein...

Es handelt sich hier nicht um keepalives sondern um simple 
Paketwiederholungen.

Schliesst du den Socket nach dem Fehler ? Es ist kein FIN oder RST zu 
sehen. Erzeugt du eine völlig neuen Socket oder versuchst du auf dem 
altem Socket weiter zu senden ?
Welche Socket bezogenden Calls spuckt strace aus ?
Welche Sockets in welchem State werden zu verschiedenden Zeitpunkten von 
netstat -anp ausgespuckt ?

P.S.: Bitte Traces in Zukunft als *.pcap hochladen.

von Peter II (Gast)


Lesenswert?

auch die anzeige von netstat -a -n würde weiterhelfen

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.