100%ig Zuverlässige TCP/IP Kommunikation...
-
Ein 100% kann es nicht geben. Wenn du eine Sequenznummer und ein Angekommen sendet musst du auf Clientseite wieder bestätigen das die Bestätigung angekommen ist.
Solange aber der Socket offen ist kannst du dir immer sicher sein das dir TCP vieles abnimmt.
Wenn die Daten bereits beim Empfänger sind dann kann der Sender schon wieder weiter machen. Der Empfänger kann zwar einen Timeout bekommen aber IMHO bekommt er das vom Treiber der den Socket steuert.
-
Jochen Kalmbach schrieb:
Hallo hustbaer!
hustbaer schrieb:
Ok, also du hast grundsätzlich 2 Fälle: "ja" -> alles angekommen wie es sollte und "nein" -> nicht angekommen.
Mittels 2x Empfang quittieren (1x Empfang der Nachricht und 1x Empfand der Bestätigung) kannst du "sicher ja" feststellen. Wenn dabei allerdings etwas daneben geht heisst das nicht "sicher nein", sondern eben "unbekannt: ja oder nein".Endlich einer der mich versteht!
Hehe, ja, weil ich eben genau so ein Problem schon hatte

hustbaer schrieb:
Was du schreibst erinnert mich daran wie ich vor dem Problem stand gewisse Daten (Events aus einem Log) zu übertragen. Dabei war wichtig dass die Daten Clientseitig erst gelöscht werden wenn sie übertragen und am Server gespeichert wurden, und dass Daten nicht 2x am Server eingetragen wurden.
Die Lösung: man verpasst jedem Datensatz Clientseitig eine unique ID (ich hab' einfach ne GUID genommen).
Dann schickt man alle Datensätze an den Server. Der Server verwirft alle Datensätze mit einer bereits bekannten GUID, alle anderen werden abgespeichert.Wenn alles abgespeichert ist schickt der Server ein ACK an den Client, woraufhin der alle übertragenen Datensätze löscht.
Wird der Vorgang unterbrochen werden einfach alle alten Datensätze bei der nächsten Übertragung nochmal mitgeschickt. Ob die dann schon eingetragen wurden oder nicht ist egal, da ja bereits eingetragene Datensätze anhand ihrere GUID erkannt und verworfen werden.
Vielleicht hilft dir das weiter.
Das ist bisher auch die Lösung die ich mir vorstellen kann... leider ist das nicht so einfach mit einer eindeutigen ID... ich müsste mir ja auf der Server-Seite *alle* IDs merken und immer nachschlagen. Das ist etwas "overpowered"...
Sowas muss es doch (einfacher) geben!!! 2-Phase-Commit-Protokoll... ich hab bloß noch nichts gefunden wie man das auf TCP anwendet...
Naja, du musst dir auf der Server Seite nur die IDs merken von Transaktionen von denen der Server nicht sicher sein kann dass der Client bereits weiss dass sie auch committed wurden, und dass der Client sie seinerseits als "fertig" markiert hat (bzw. einfach gelöscht hat).
Nachdem der Server eine Transaktion "committed" hat schickt er einfach zum Client "Transaktion #1234 ist committed". Der Client kann nun seinerseits diese Transaktion löschen bzw. als "fertig" markieren, und _danach_ schickt er an den Server "OK, habe Transaktion #1234 als fertig markiert". Sobald der Server das empfangen hat kann er die Daten über Transaktion #1234 löschen, da er sicher sein kann diese vom Client nicht nochmals geschickt zu bekommen.
Das einzige was hier nun passieren kann ist dass der Server eine Transaktion (die bereits committed ist) für einen Client noch gespeichert hat, der Client diese aber schon gelöscht hat (da die Verbindung unterbrochen wurde bevor der Client das "OK, habe Transaktion #1234 als fertig markiert" an den Server schicken konnte).
Der Fall ist aber nicht weiter tragisch, das lässt sich einfach damit regeln dass bei jedem Verbindungsaufbau der Server die IDs der Transaktionen die bereits committed wurden an den Client schickt, und der Client diese dann auf seiner Seite löscht. Hat er sie schon gelöscht findet er sie nicht und ignoriert sie einfach, in dem Fall schickt er dann ein "OK, habe Transaktion #1234 nicht gefunden, muss ich damals schon gelöscht haben" an den Server, und dieser kann die Daten wiederum löschen.Soetwas würde ich allerdings nur implementieren wenn das System nicht sowieso Daten über sämtliche Transaktionen irgendwo aufheben muss. Das Nachschlagen der IDs sehe ich nicht als Problem ansich, höchstens eben den Speicherplatz der dafür draufgeht, was aber eben nur ein Problem ist wenn nicht sowieso alles aufgehoben werden muss.
Das Nachschlagen in einer kleinen Detailtabelle (bzw. einem "Covering Index") mit nur Transaktions ID + Zustand sollte auf jeden Fall sehr schnell gehen - so eine GUID ist gerademal 16 Byte lang, mit Zustand und Overhead kommt das auf sagen wir mal 17-20 Byte pro Zeile - regt mich ehrlich gesagt nicht sonderlich auf. So viele Zeilen können das garnicht sein dass ein B-Baum da besonders tief werden könnte.
Und wenn man statt GUIDs noch fortlaufende Nummern vergibt muss auch nur ein ganz kleiner Teil dieser Tabelle im Speicher gehalten werden, nämlich die IDs der letzten paar Tage.
(Und wenn man die IDs Serverseitig vergibt sollte man auch mit 8 oder 10 Byte auskommen, was die Tabelle nochmal schmäler macht)p.S.: über Timeouts oder die Details von TCP/IP muss (bzw. sollte oder noch besser: darf) man sich bei sowas überhaupt keine Gedanken machen. Man behandelt die TCP/IP Verbindung einfach als Verbindung die jederzeit abreissen kann, und wenn sie abreisst muss man davon ausgehen dass minimal garnix bis maximal alles was seit der letzten Bestätigung zur Gegenstelle geschickt wurde nicht angenommen ist. Dadurch erübrigt es sich auch darüber nachzudenken ob die Gegenstelle vielleicht abstürzen könnte oder den Strom verliert oder sonstwas -- wenn das Protokoll mit "Verbindung kann jederzeit abreissen" klarkommt sind diese Fälle alle automatisch mit abgedeckt.
-
IMHO ist sein Problem ja nicht die TCP-Verbindung. Die Daten landen ja auf dem Client wenn sie vom Server gesendet wurden. Er hat ein Problem auf Daten der Netzwerkebenen 3 (wo die Daten bereits im BS-Buffer liegen) und bekommt beim Abfrage einen Timeout. (wie auch immer dieser dann aussieht den eigetlich macht dies der Treiber bzw. Protokoll ).
Wenn er nun ein OK sendet liegen diese Daten dann auch im Buffer und er kann diese wieder nicht abholen. Da musst er dann ein OK für ein OK und wieder eine OK für dieses OK u.s.w. senden.
IMHO weiß ich nicht ob der Timeout nicht sowieso vom Treiber selbst kommt dem man sagt das er nach X Sekunden timeouten soll und dann die Verbindung beendet. Das bekomme auch beide Seiten mit.
Wenn die Daten bereits im Buffer des Empfängers liegen dann sollte es eigetlich nie eine Fall geben das man die nicht bekommet. Somit kann der Sender sicher sein das die Daten beim Client angekommen sind. Kommen sie dort nicht an regelt dies TCP selbst.
-
Unix-Tom schrieb:
IMHO ist sein Problem ja nicht die TCP-Verbindung. Die Daten landen ja auf dem Client wenn sie vom Server gesendet wurden. Er hat ein Problem auf Daten der Netzwerkebenen 3 (wo die Daten bereits im BS-Buffer liegen) und bekommt beim Abfrage einen Timeout. (wie auch immer dieser dann aussieht den eigetlich macht dies der Treiber bzw. Protokoll ).
Wenn er nun ein OK sendet liegen diese Daten dann auch im Buffer und er kann diese wieder nicht abholen. Da musst er dann ein OK für ein OK und wieder eine OK für dieses OK u.s.w. senden.
IMHO weiß ich nicht ob der Timeout nicht sowieso vom Treiber selbst kommt dem man sagt das er nach X Sekunden timeouten soll und dann die Verbindung beendet. Das bekomme auch beide Seiten mit.
Wenn die Daten bereits im Buffer des Empfängers liegen dann sollte es eigetlich nie eine Fall geben das man die nicht bekommet. Somit kann der Sender sicher sein das die Daten beim Client angekommen sind. Kommen sie dort nicht an regelt dies TCP selbst.Tut mir leid aber das ist ganz grosser Blödsinn.
TCP/IP kann z.B. schonmal garnixmehr regeln wenn ich den Netzwerkstecker gezogen habe, das Modem abgeraucht ist, der Strom ausgefallen oder was auch immer.
TCP/IP unternimmt auch nix besonderes wenn es mal entschieden hat dass eine Verbindung unterbrochen wurde.Das eigentliche Problem hat mit TCP/IP *nichts* zu tun und kann auch nicht von TCP/IP gelöst werden.
Das eigentliche Problem nennt sich "distributed transactions".
-
TCP Regel sehr wohl ob ein Packet angekommen ist, doppelt vorhanden ist, in falscher Reihenfolge angekommen ist u.s.w.
Es geht ja nicht darum den Verkehr zwiscchen Puffer Sender und Puffer Empfänger sicher zu machen. Dies macht TCP.
Deshalb nennt man es ja Transmission Control Protocol.
Kommt ein Packet in einem vereinbarten Timeout nicht beim Empfänger an sender der Sender nochmals.
-
Unix-Tom schrieb:
TCP Regel sehr wohl ob ein Packet angekommen ist, doppelt vorhanden ist, in falscher Reihenfolge angekommen ist u.s.w.
Es geht ja nicht darum den Verkehr zwiscchen Puffer Sender und Puffer Empfänger sicher zu machen. Dies macht TCP.
Deshalb nennt man es ja Transmission Control Protocol.
Kommt ein Packet in einem vereinbarten Timeout nicht beim Empfänger an sender der Sender nochmals.Alles richtig. Das ermöglicht aber nur eine "sichere" FIFO Verbindung *solange die Verbindung nicht abreisst*.
Wenn die Verbindung erstmal abgerissen ist kann TCP/IP aber auch nix mehr regeln, das ist es was ich meine. Und eben den Punkt dass der Umstand dass man etwas senden konnte nicht bedeutet dass es auch empfangen werden konnte.Daher ist TCP/IP für distributed transactions nicht ausreichend, und man muss selbst entsprechende Mechanismen implementieren damit das geht.
-
hustbaer schrieb:
Und eben den Punkt dass der Umstand dass man etwas senden konnte nicht bedeutet dass es auch empfangen werden konnte.
doch, schon, daten werden vom empfänger bestätigt. kommte keine bestätigung, versucht's der sender nochmal. ist im TCP alles schon eingebaut. wenn die verbindung fehlerfrei geschlossen wird, haben beide teilnehmer alles bekommen, was der andere gesendet hat.
-
pale dog schrieb:
hustbaer schrieb:
Und eben den Punkt dass der Umstand dass man etwas senden konnte nicht bedeutet dass es auch empfangen werden konnte.
doch, schon, daten werden vom empfänger bestätigt. kommte keine bestätigung, versucht's der sender nochmal. ist im TCP alles schon eingebaut. wenn die verbindung fehlerfrei geschlossen wird, haben beide teilnehmer alles bekommen, was der andere gesendet hat.
Nein eben nicht! Du redest hier nur von Ebene 3 und da stimmt das alles auch... meine Anwendung läuft aber auch Ebene 8!
Und da kann ich z.B. genau in dem Zeitpunkt in einen Timeout laufen, während das Paket gerade auf Ebene 3 als angekommen bestätigt wurde...Das Warten geschieht übrigens mittels "WSAWaitForMultipleEvents", wobei man ja den Timeout angeben kann. Und vorbereitet wird der Socket mittels "WSAAsyncSelect und FD_READ|FD_CLOSE".
-
Jochen Kalmbach schrieb:
Nein eben nicht! Du redest hier nur von Ebene 3 und da stimmt das alles auch... meine Anwendung läuft aber auch Ebene 8!
Und da kann ich z.B. genau in dem Zeitpunkt in einen Timeout laufen, während das Paket gerade auf Ebene 3 als angekommen bestätigt wurde...ja, das kann passieren, aber wenn du beim timeout z.b. den socket killst, kriegt die gegenstelle das mit und weiss, dass obwohl sie alles senden konnte, du die kommunikation abgebrochen hast. selbst wenn die gegenstelle schon die close-sequenz gestartet hat, bemerkt sie ein killen der verbindung deinerseits.
ist das netz down o.ä. und die gegenstelle bekommt deinen erzwungenen verbindungsabbruch nicht mit, dann misslingt auch das von ihr initiierte schliessen der verbindung. in allen fällen klappt die erkennung, erfolg oder misserfolg, sehr zuverlässig. wenn's nicht so wäre, würde das ganze internet verdammt schlecht funktionieren
Jochen Kalmbach schrieb:
Das Warten geschieht übrigens mittels "WSAWaitForMultipleEvents", wobei man ja den Timeout angeben kann. Und vorbereitet wird der Socket mittels "WSAAsyncSelect und FD_READ|FD_CLOSE".
beim FD_CLOSE kannste ja mit dem 'lparam' o.ä. herausfinden, ob irgendwas schief ging. alle wichtigen events sollten eigentlich bis zum layer 8 irgendwie durchgereicht werden...
-
pale dog schrieb:
hustbaer schrieb:
Und eben den Punkt dass der Umstand dass man etwas senden konnte nicht bedeutet dass es auch empfangen werden konnte.
doch, schon, daten werden vom empfänger bestätigt. kommte keine bestätigung, versucht's der sender nochmal. ist im TCP alles schon eingebaut. wenn die verbindung fehlerfrei geschlossen wird, haben beide teilnehmer alles bekommen, was der andere gesendet hat.
Äh. Das ist mir schon klar dass das gilt wenn die Verbindung "gracefully closed" wurde.
Bloss was ist wenn sie abreisst?
Was bringt mir ein Protokoll welches nur dann "korrekt" funktioniert wenn die Verbindung nie abreisst?
Verstehe das nicht so ganz... *wunder*
-
hustbaer schrieb:
Bloss was ist wenn sie abreisst?
wenn die verbindung abreisst dann muss die ganze sendung irgendwann wiederholt werden (unter der voraussetzung, dass beide 100%ige gewissheit brauchen).
hustbaer schrieb:
Was bringt mir ein Protokoll welches nur dann "korrekt" funktioniert wenn die Verbindung nie abreisst?
kein verbindungsorientiertes protokoll funktioniert richtig, wenn die verbindung abreisst

btw: ich weiss, dass manche lieber ihre eigenen protokolle mit irgendwelchen packet-ID's und acknowledgements auf TCP aufsetzen, anstatt einer seit jahrzehnten bewährten technik zu vertrauen, aber dann kann man besser gleich UDP nehmen.
das geht dann meistens sogar schneller
-
pale dog schrieb:
hustbaer schrieb:
Bloss was ist wenn sie abreisst?
wenn die verbindung abreisst dann muss die ganze sendung irgendwann wiederholt werden (unter der voraussetzung, dass beide 100%ige gewissheit brauchen).
hustbaer schrieb:
Was bringt mir ein Protokoll welches nur dann "korrekt" funktioniert wenn die Verbindung nie abreisst?
kein verbindungsorientiertes protokoll funktioniert richtig, wenn die verbindung abreisst

btw: ich weiss, dass manche lieber ihre eigenen protokolle mit irgendwelchen packet-ID's und acknowledgements auf TCP aufsetzen, anstatt einer seit jahrzehnten bewährten technik zu vertrauen, aber dann kann man besser gleich UDP nehmen.
das geht dann meistens sogar schneller
Ich meinte mit "Protokoll" nicht TCP/IP sondern ein "Anwendungsprotokoll" welches auf TCP/IP (oder sonstwas) aufsetzt. Eben etwas mit dem ich verteilte Transaktionen machen kann, oder eben so eine "100%ige Sicherheit" bekommen kann.
Vielleicht habe ich Jochen doch nicht richtig verstanden, aber ich habe den Eindruck dass es darum geht einen Fall wo die Verbindung abgerissen ist richtig zu handhaben. Und wenn die Verbindung abgerissen ist können eben die netten Garantien von TCP/IP die nur für den Fall gelten wo die Verbindung nicht abgerissen ist auch logischerweise nicht helfen. Klar jetzt was ich meine?
-
hustbaer schrieb:
Vielleicht habe ich Jochen doch nicht richtig verstanden, aber ich habe den Eindruck dass es darum geht einen Fall wo die Verbindung abgerissen ist richtig zu handhaben.
das hab' ich auch so verstanden.
hustbaer schrieb:
Und wenn die Verbindung abgerissen ist können eben die netten Garantien von TCP/IP die nur für den Fall gelten wo die Verbindung nicht abgerissen ist auch logischerweise nicht helfen. Klar jetzt was ich meine?
klar, aber wenn die verbindung abgerissen ist, kann gar nichts mehr helfen, ausser vielleicht irgendwelche alternativen kommunikationswege. das wichtigste aber ist doch, dass beide kommunikationspartner feststellen können, das irgendwas schief gegangen ist und das bringt TCP schon mit.
es gibt keine absolute sicherheit, dass die übertragung immer klappt.
denn wenn das netz tot ist, helfen auch keine auf TCP aufgesetzten protokolle mehr.

-
Selbst wenn die Verbindung abreißt. Den Timeout verursacht doch nicht Ebene 8 oder ire ich mich da. Man teil der API doch mit wann der Timeout kommen soll. Wenn ein Timeout dann auf TCP-Ebene da ist dann sendet der Empfänger auch kein OK mehr an den Server und teil dem Programm mit das ein Timeout da ist.
Habe Jochen vielleicht auch falsch verstanden.
Ich verstehe aber nicht was Schicht 3 ist den TCP im OSI-Model läuft in Schicht 4 und das Programm selbst in Schicht 7. Schicht 3 ist das Netzwerk selbst.
Schicht 4 ist das Protokoll. Schicht 7 macht nur das was im die Darunterliegenden Mitteilen.
-
Unix-Tom schrieb:
Selbst wenn die Verbindung abreißt. Den Timeout verursacht doch nicht Ebene 8 oder ire ich mich da.
das core TCP protocol kennt keine time-outs während eine verbindung steht, aber der socket-layer bietet eine keepalive-option an, um die verbindung zu checken. dabei werden, falls lange nichts los war, pakete ohne inhalt (also nur die header) verschickt, die der andere beantworten muss.

-
TCP ist immernoch ein 4-Schichtenmodell bevor es ISO-8-Schichtenmodelle gabs

-
Dann sagen wir Schicht 4 (TCP) und 7 (Application-Layer)... sorry... jeweils um eins verrutscht... aber um das geht es mir ja gar nicht

http://de.wikipedia.org/wiki/OSI-ModellIch wiess nicht wie Windows das abhandelt, aber aus der Erfahrung raus wird der Timeout nicht in Ebene 4 gemacht sondern weiter oben... denn sonst hätte ich das Problem ja nicht

-
Wenn du einen Timeout bekommst dann hast du aber noch immer Daten im Buffer (wurden ja auch in Schicht 3 bereits an den Sender mit OK bestätigt) die du dann trotzdem noch holen kannst oder hast du nach Timeout keine Zugriff mehr auf den Socket um ein Read auszuführen.
-
Das hilft mir aber vermutlich auch nicht, da es dann wieder eine andere Race-Condition gibt, zwischen dem "timeout", "lesen" und "zurücksetzen" des Sockets...
Ich werd wohl nicht über eine eindeutige ID drum rum kommen...Danke für die vielen Beiträge!
-
pale dog schrieb:
hustbaer schrieb:
Vielleicht habe ich Jochen doch nicht richtig verstanden, aber ich habe den Eindruck dass es darum geht einen Fall wo die Verbindung abgerissen ist richtig zu handhaben.
das hab' ich auch so verstanden.
hustbaer schrieb:
Und wenn die Verbindung abgerissen ist können eben die netten Garantien von TCP/IP die nur für den Fall gelten wo die Verbindung nicht abgerissen ist auch logischerweise nicht helfen. Klar jetzt was ich meine?
klar, aber wenn die verbindung abgerissen ist, kann gar nichts mehr helfen, ausser vielleicht irgendwelche alternativen kommunikationswege. das wichtigste aber ist doch, dass beide kommunikationspartner feststellen können, das irgendwas schief gegangen ist und das bringt TCP schon mit.
Richtig. Bloss kann z.B. der Kommunikationspartner der zuletzt noch gesendet hat nicht wissen wieviel schon beim anderen angekommen ist.
es gibt keine absolute sicherheit, dass die übertragung immer klappt.
denn wenn das netz tot ist, helfen auch keine auf TCP aufgesetzten protokolle mehr.

Wenn das Netzt tot ist kann man solange nixmehr machen bis man wieder ein Netz hat. Dann kann man nen neue Verbindung aufbauen und von vorne anfangen. Um aber von vorne anfangen zu können und dabei nicht Gefahr zu laufen Daten doppelt abzuspeicher/Dinge doppelt zu machen muss man selbst irgendwie dafür sorgen dass beim "Wiederaufnehmen" eines Vorganges ermittelt werden kann auf welcher Seite welcher Teil bereits ausgeführt wurde.
@Jochen Kalmbach: vergiss die Schichten, darum gehts nicht

Wenn du irgendwo einen Fehler feststellst mach den Socket zu und ignorier einfach alles was du noch nicht gelesen hast. Dein (Applikations-)Protokoll muss sowieso damit klarkommen dass jederzeit die Verbindung getrennt werden kann. Wenn es passiert, und du noch ein paar Pakete von der Gegenstelle im Empfangspuffer stehen hast die du dann nichtmehr auswertest - egal, der Abbruch hätte genausogut vor dem Empfangen dieser Pakete stattfinden können.