Entwickler-Ecke
Internet / Netzwerk - Daten welche bereits dem Stack übergeben wurden löschen?
sky21 - Do 23.12.10 09:24
Titel: Daten welche bereits dem Stack übergeben wurden löschen?
Hi all
Die Daten stecken im XP/W7 TCP/IP Stack fest!
Meine Applikation übergibt grosse Datenblöcke (64k) an den Windows TCP/IP Stack. Geht die Geschwindigkeit herunter (gegen 0), so wird die Verbindung von der Applikation abgebrochen und die beteiligten Objekte (TIdFTP od. TIdHTTP) aufgeräumt.
Offenbar kommt es aber nun vor, dass Restdaten immer noch im Windows TCP/IP Stack liegen. Aufgrund der aktuellen Netzgeschwindigkeit (undendlich langsam), können diese nicht od. nur langsam gesendet werden.
Meine Hypothese: Weil im Stack offenbar immer noch Daten sind, verhindern diese, dass eine neue TCP Verbindung aufgebaut werden kann bzw. es muss zuerst gewartet werden, bis die alten Daten raus gesendet wurden.
Frage: Gibt es eine Möglichkeit, dem TCP/IP Stack von Windows ein "Clear()" zu senden?
Befehle wie "netsh winsock reset" oder "netsh int ip reset" bewirken keine Lösung.
Narses - Do 23.12.10 12:12
Moin!
sky21 hat folgendes geschrieben : |
| Meine Applikation übergibt grosse Datenblöcke (64k) an den Windows TCP/IP Stack. |
Es war schon immer problematisch, wenn man mehr als MTU als Paketgröße verwendet, das mal vorab. :idea: Und ja, ich weiß, dass man das machen
kann, aber deswegen gibt es - offensichtlich :zwinker: - trotzdem die Probleme. :nixweiss: Und sei es nur, eine Socket-Verbindung wieder zu kappen...
sky21 hat folgendes geschrieben : |
| Geht die Geschwindigkeit herunter (gegen 0), so wird die Verbindung von der Applikation abgebrochen und die beteiligten Objekte (TIdFTP od. TIdHTTP) aufgeräumt. |
Da Indy mit blocking socket calls arbeitet ist die spannende Frage, ob noch ein Call pendig ist, wenn du "abbrichst" (wie auch immer du das tust). Wenn da noch ein WSA-Call läuft, wird der auch durchgezogen, das ist klar. Und wenn du dann einen fetten Block losgetreten hast und die WSA den zwar los wird, aber nur langsam, hast du Pech gehabt. Mir ist keine Methode bekannt, wie man das abbrechen kann. Mal in die WSA-API-Doku reingesehen? :les: :nixweiss:
AFAIR wird alles, was mit einer TCP-Verbindung in der WSA assoziiert ist, mit dem Freigeben des Socket-Handles auch freigegeben. Allerdings erst, wenn der letzte blocking call durch ist. Und deshalb ist es gar keine so schlechte Idee, sich an der MTU (oder knapp drüber, aber auf jeden Fall nicht mit 64k-Blöcken) zu orientieren. :idea:
cu
Narses
BenBE - Do 23.12.10 12:29
Ferner gibt es nicht umsonst bei TCP den Nagle-Algorithmus, der automatisch passende Blöcke generiert. Also viele kleine Blöcke lostreten und die WSA selber entscheiden lassen, mit welcher Block-/Packet-Größe die über's Äther-Netz geschoben werden.
P.S.: Man kann mit via Urgent-Flag gesendeten Daten nen Stream-Clear erzwingen, was z.B. bei SSH bzw. Telnet benutzt wird, um bei lahmen Verbindungen einen Resync auszuführen. Das Verhalten der TCP-Stack-Implementierungen hierbei ist aber nicht portabel und strengstens Implementationsabhängig. Zusätzlich müssen sich Sender UND Empfänger über die Verwendung einig sein.
sky21 - Mo 03.01.11 14:37
BenBE hat folgendes geschrieben : |
Ferner gibt es nicht umsonst bei TCP den Nagle-Algorithmus, der automatisch passende Blöcke generiert. Also viele kleine Blöcke lostreten und die WSA selber entscheiden lassen, mit welcher Block-/Packet-Größe die über's Äther-Netz geschoben werden.
|
Gegen diese Aussage spricht jedoch, dass "immer" eine Buffersize gesetzt wird. Indy default ist irgendwas bei 16k.
So oder so: Neues Jahr aber trotzdem noch das alte Problem.
Habe noch etwas Interessantes zum WSACleanup() gelesen:
Zu detusch: Die Daten könnten verloren sein, wenn Cleanup() aufgerufen wird. Perfekt oder?
Allerdings: Ein Demoprogramm, welches alternierend WSAStartup() WSACleanup() aufruft, funktioniert genau nur 1 Mal! Danach meldet WSACleanup() fehler ... (Error: 10093). Verstehe ich jetzt wirklich nicht. Anybody else? Danke!
Delete - Mo 03.01.11 14:49
Dann solltest du dir mal den Klartext zum Fehlercode ausgeben lassen:
| Zitat: |
| Die Anwendung hat die Funktion WSAStartup nicht aufgerufen, oder bei dieser Funktion ist ein Fehler aufgetreten. |
sky21 - Mo 03.01.11 14:59
Luckie hat folgendes geschrieben : |
Dann solltest du dir mal den Klartext zum Fehlercode ausgeben lassen:
| Zitat: | | Die Anwendung hat die Funktion WSAStartup nicht aufgerufen, oder bei dieser Funktion ist ein Fehler aufgetreten. |
|
Nun, ganz so einfach ist es auch wieder nicht!
Delphi-Quelltext
1: 2: 3: 4:
| WSAStartup(wVersionRequested, wsaData); WSACleanup(); WSAStartup(wVersionRequested, wsaData) WSACleanup(); |
Mache ich noch irgend etwas Interessantes zwischen Startup und Cleanup (z.B. Datei Herunterloaden mit IdHttp), so sieht ist das Verhalten wieder ganz anders. Mal geht es, mal nicht... Offenbar verwendet Indy auch ab und zu ein Startup()/Cleanup(). Dem muss ich noch weiter nachgehen.
Interessanterweise gibt Cleanup() auch die DLL (WS2_32.dll) nicht frei. Zumindest ist diese im process explorer noch sichtbar.
Moderiert von
Narses: Delphi-Tags hinzugefügt
Narses - Mo 03.01.11 15:09
Moin!
sky21 hat folgendes geschrieben : |
BenBE hat folgendes geschrieben : | Ferner gibt es nicht umsonst bei TCP den Nagle-Algorithmus, der automatisch passende Blöcke generiert. Also viele kleine Blöcke lostreten und die WSA selber entscheiden lassen, mit welcher Block-/Packet-Größe die über's Äther-Netz geschoben werden.
| Gegen diese Aussage spricht jedoch, dass "immer" eine Buffersize gesetzt wird. Indy default ist irgendwas bei 16k. |
Vorsicht, bitte nicht Senden und Empfangen durcheinander bringen. :idea:
sky21 hat folgendes geschrieben : |
| So oder so: Neues Jahr aber trotzdem noch das alte Problem. |
Wie wäre es denn mal mit einem Test mit kleinerer Blocksize? :nixweiss: Nur für den Fall, dass wir hier doch keinen Unsinn reden... ? ;)
sky21 hat folgendes geschrieben : |
Habe noch etwas Interessantes zum WSACleanup() gelesen:
Zu detusch: Die Daten könnten verloren sein, wenn Cleanup() aufgerufen wird. Perfekt oder? |
Wenn du mit blocking socket calls arbeitest (und Indy tut das), dann wird der letzte Call durchgezogen, egal was du der WSA sagst, was sie tun soll(te). Da bin ich mir sehr sicher. :!:
cu
Narses
sky21 - Mo 03.01.11 15:29
| Narses hat folgendes geschrieben: |
Wenn du mit blocking socket calls arbeitest (und Indy tut das), dann wird der letzte Call durchgezogen, egal was du der WSA sagst, was sie tun soll(te). Da bin ich mir sehr sicher. :!:
cu
Narses |
Das ist eine sehr Interessante Aussage und für mich gleich auch enttäuschen. D.h. ich bin definitiv wieder am Anfang.
Narses, hast du vielleicht noch eine Idee, wie man den Stack instruieren kann, die Daten doch nicht mehr zu senden?
Narses - Mo 03.01.11 16:22
Moin!
sky21 hat folgendes geschrieben : |
| Narses, hast du vielleicht noch eine Idee, |
Sorry, aber ich muss mich wiederholen:
Narses hat folgendes geschrieben : |
| Wie wäre es denn mal mit einem Test mit kleinerer Blocksize? :nixweiss: Nur für den Fall, dass wir hier doch keinen Unsinn reden... ? ;) |
Was soll denn diese große Blocksize für einen unschlagbaren Vorteil haben, dass man darauf nicht verzichten kann. Ich kann mir nicht vorstellen, dass es da so riesige Performance-Einbußen geben soll (noch dazu ist das Handling von Paketen >MTU nicht für jeden TCP-Stack im Netz vorhersagbar, es kann also durchaus sein, dass bei einem Linux-Stack nicht der gewünschte Effekt eintritt (ist nur ein Beispiel)). :nixweiss:
sky21 hat folgendes geschrieben : |
| wie man den Stack instruieren kann, die Daten doch nicht mehr zu senden? |
Eine dokumentierte Möglichkeit ist mir nicht bekannt. Alternativ könnte man mit non-blocking-socket calls arbeiten und den Socket schließen, das sollte evtl. klappen (hatte mal ähnliche Probleme untersucht, da ging das Verhalten der WSA in deine gewünschte Richtung). Aber Vorsicht: ereignisorientierte Socket-Verbindungen sind deutlich schwerer stabil zu handeln, als blocking calls in Threads! (Noch dazu gibt es vermutlich keine Komponenten dafür :?:)
cu
Narses
sky21 - Di 04.01.11 10:18
Narses hat folgendes geschrieben : |
Wie wäre es denn mal mit einem Test mit kleinerer Blocksize? :nixweiss: Nur für den Fall, dass wir hier doch keinen Unsinn reden... ? ;)Was soll denn diese große Blocksize für einen unschlagbaren Vorteil haben, dass man darauf nicht verzichten kann. Ich kann mir nicht vorstellen, dass es da so riesige Performance-Einbußen geben soll (noch dazu ist das Handling von Paketen >MTU nicht für jeden TCP-Stack im Netz vorhersagbar, es kann also durchaus sein, dass bei einem Linux-Stack nicht der gewünschte Effekt eintritt (ist nur ein Beispiel)). :nixweiss:
|
Mit Blocksize meine ich übrigends das da: (Nicht zu verwechseln mit der Window (Receive) Size)
Delphi-Quelltext
1:
| FFTP.IOHandler.SendBufferSize := 65535; |
Bei Uploads (FTP Put, HTTP Put) ist tatsächlich ein Unterschied beim Datendurchsatz feststellbar. Habe diverse Grössen ausprobiert.
Aber das ist eher ein anderes Thema (welches ich auch sep. hier thematisiere, hehe).
Narses - Di 04.01.11 14:01
Moin!
sky21 hat folgendes geschrieben : |
Mit Blocksize meine ich übrigends das da: (Nicht zu verwechseln mit der Window (Receive) Size)
Delphi-Quelltext 1:
| FFTP.IOHandler.SendBufferSize := 65535; |
Bei Uploads (FTP Put, HTTP Put) ist tatsächlich ein Unterschied beim Datendurchsatz feststellbar. Habe diverse Grössen ausprobiert. |
Ah, das sollte allerdings unkritisch sein, OK.
Tja, dann fällt mir nur noch "schmutziges" ein... :? On-the-fly die Routing-Tabelle ändern und diesen Host ins Nirvana leiten, bis der Socket freigegeben ist, oder die Schnittstelle kurz deaktivieren, das sollte auf jeden Fall jeglichen Transfer resp. WSA-Aktion in einen Fehler laufen lassen... :hair: :nixweiss: Empfehlen kann ich davon aber nicht wirklich was.
cu
Narses
sky21 - Di 04.01.11 15:18
Narses hat folgendes geschrieben: |
Tja, dann fällt mir nur noch "schmutziges" ein... :? On-the-fly die Routing-Tabelle ändern und diesen Host ins Nirvana leiten, bis der Socket freigegeben ist, oder die Schnittstelle kurz deaktivieren, das sollte auf jeden Fall jeglichen Transfer resp. WSA-Aktion in einen Fehler laufen lassen... :hair: :nixweiss: Empfehlen kann ich davon aber nicht wirklich was.
cu
Narses |
Hmm, Routing Table... Nette Idee! Ob ich mir die Daten selber auf's Loopback pusten könnte? Wäre einmal ein Versuch wert. Das Deaktivieren der Karte ist leider nicht möglich; da gibts dann wieder ganz andfere Probleme.
sky21 - Fr 07.01.11 10:41
Update:
Habe herausgefunden, dass mit der grossen Buffersize nicht die Socketsize selber modifiziert wird. D.h. die Socketgrösse ist weiterhin 8192 Bytes gross.
Mein ursprüngliches Problem, dass die Daten trotz Abbruch bzw. Objektfreigabe weiterhin verarbeiten werden, scheint womöglich Indy intern zu sein:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41:
| procedure TIdIOHandler.WriteDirect(const ABuffer: TIdBytes; const ALength: Integer = -1; const AOffset: Integer = 0); var LTemp: TIdBytes; LPos: Integer; LSize: Integer; LByteCount: Integer; LLastError: Integer; begin CheckForDisconnect(True, True); LTemp := ToBytes(ABuffer, ALength, AOffset); if Intercept <> nil then begin Intercept.Send(LTemp); end; LSize := Length(LTemp); LPos := 0; while LPos < LSize do begin LByteCount := WriteDataToTarget(LTemp, LPos, LSize - LPos); if LByteCount < 0 then begin LLastError := GStack.CheckForSocketError(LByteCount, [ID_WSAESHUTDOWN, Id_WSAECONNABORTED, Id_WSAECONNRESET]); FClosedGracefully := True; Close; GStack.RaiseSocketError(LLastError); end; TIdAntiFreezeBase.DoProcess(False); if LByteCount = 0 then begin FClosedGracefully := True; end; CheckForDisconnect; DoWork(wmWrite, LByteCount); Inc(LPos, LByteCount); end; end; |
So wie ich das erkenne scheint der Buffer (in meinem Fall 64k) mittels while Schlaufe abgearbeitet zu werden. Unabhängig davon, ob von Aussen (z.B. TIdFTP->ABOR) aufgerufen wird. WriteDataToTarget() wird folgedessen aufgerufen, bis der Buffer leer ist.
Interessanterweise bin ich der Meinung, dass ich alle Objekte korrekt freigebe. Läuft da Indy womöglich trotzdem weiter? Das kann ich nicht ganz ausschliessen. Aber auch mein eigener Code muss nicht fehlerfrei sein, trotz X-maligem review ...
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!