Hallo, ich bastle an einem Kommunikationsprotokoll zwischen Clients und einem Server. Die Kommunikation erfolgt über UDP (kann nicht geändert werden). Da kann es vorkommen, dass Pakete verlorengehen oder beschädigt ankommen. In einem Teil der Pakete werden Anweisungen zum Eintragen von Daten in in eine Datenbanken zum Server gesendet. Diese Pakete beantwortet der Server mit einer Quittung. Sollte eine solche Quittung beim Client nicht ankommen, kann das zwei Ursachen haben: a) das ursprüngliche Paket ist beim Server nicht angekommen, also wird auch keine Quittung gesendet b) die Quittung ist verlorengegangen Der Client wartet immer eine gewisse Zeit auf die Quittung und sendet dann das ursprüngliche Paket evtl. nochmal. Im Falle, dass nur die Quittung verlorengegenagen ist, erfolgt dann aber die Eintragung in die Datenbank doppelt - sofern man keine zusätzliche Absicherung betreibt. Um das zu verhindern gebe ich jedem Paket einen Timestamp mit, der im Falle einer Wiederholung unverändert bleibt und die Kennung, dass es sich um ein wiederholtes Paket handelt. So kann der Server nachsehen, ob er das Paket schon mal vor Kurzem verarbeitet hat. Das funktioniert auch soweit ganz gut, ist aber ziemlich aufwändig, z.B. muss eine Liste der zuletzt verarbeiteten Pakete geführt werden. Hat hier evlt. jmd. noch einen Tip für einen celevereren Algorithmus? Danke. Frank
"(kann nicht geändert werden)." Das ist allerdings bloed, weil eigentlich willst du ein hoeheres RPC-Protokoll (DCE, ONCRPC, SOAP, whatever...) fuer so etwas nutzen.
Frank schrieb: > Um das zu verhindern gebe ich jedem Paket einen Timestamp mit, der im > Falle einer Wiederholung unverändert bleibt und die Kennung, dass es > sich um ein wiederholtes Paket handelt. So kann der Server nachsehen, ob > er das Paket schon mal vor Kurzem verarbeitet hat. > > Das funktioniert auch soweit ganz gut, ist aber ziemlich aufwändig, z.B. > muss eine Liste der zuletzt verarbeiteten Pakete geführt werden. Hat > hier evlt. jmd. noch einen Tip für einen celevereren Algorithmus? Danke. Schau mal, wie es bei TCP gemacht wird, nämlich mittels Sequenz-Nummern. Wenn du dazu die Annahme machen kannst, dass sich Pakete niemals "überholen" oder das nur sehr wenige Pakete betrifft, scheint mir das viel effizienter zu sein, als mit Timestamps und Retransmit-Kennungen zu hantieren.
Frank schrieb: > Um das zu verhindern gebe ich jedem Paket einen Timestamp mit, der im > Falle einer Wiederholung unverändert bleibt und die Kennung, dass es > sich um ein wiederholtes Paket handelt. So kann der Server nachsehen, ob > er das Paket schon mal vor Kurzem verarbeitet hat. Das mit der expliziten Retransmit-Kennung als Signal "schau in der Liste" solltest du lassen, wenn die Kommunikation in einer nicht von dir selbst vollständig kontrollierten Umgebung erfolgt (und eigentlich nichtmal dann). Es kann vorkommen, dass Pakete bei der Übertragung verdoppelt werden, und das ist durchaus keine rein theoretische Möglichkeit, sondern das habe ich schon einige Male auch selbst real gesehen. Mit Sequenznummern braucht sich der Empfänger keine Liste der letzten Pakete merken, sondern er muss nur die aktuelle Sequenznummer speichern. Er muss dann bei einem empfangenen Paket nur die Nummer des Paketes mit seiner eigenen aktuellen Nummer vergleichen: - Ist sie kleiner oder gleich der eigenen, dann darf das Paket nicht erneut bearbeitet werden, es muss aber trotzdem ein ACK gesendet werden. - Ist sie exakt eins grösser als die eigene, wird das Paket bearbeitet, ein ACK gesendet und die eigene Nummer um eins erhöht. - Ist sie mehr als eins grösser als die eigene, wird das Paket einfach verworfen, der Sender sendet das dann ja später erneut, und bis dahin sind dann hoffentlich auch die fehlenden Pakete "dazwischen" eingetroffen. Das Verwerfen von Paketen im letzten Fall oben führt zu suboptimalem Verhalten, wenn die Reihenfolge der Pakete unterwegs geändert wurde, da Pakete verworfen werden, die eigentlich korrekt angekommen sind. In sehr vielen Fällen tritt das in der Praxis aber nur selten auf, weshalb es meist nicht lohnt, den Zusatzaufwand dafür zu betreiben. Der Aufwand wäre im wesentlichen so hoch, dass man auch gleich TCP benutzen könnte. Was du noch brauchst ist ein Synchronisationsmechanismus, mit dem am Anfang der Kommunikation (oder dann wenn zuviele Pakete zwischendurch verloren gehen, so dass der Sender irgendwann aufgibt) die Sequenznummern von Sender und Empfänger auf den gleichen Stand gebracht werden. Am besten schaust du dir dazu mal den Three-Way-Handshake von TCP an. Andreas
Ergänzung: auch für den Sender bringt dieses Sequenznummern-Verfahren in einigen Fällen eine Verringerung des Aufwandes mit sich. Angenommen, das letzte ACK hatte die Nummer 4, die Zähler bei Sender und Empfänger stehen also beide auf 4. Jetzt werden die Pakete 5, 6, 7 und 8 gesendet, vom Empfänger bearbeitet und geACKt, es gehen jedoch die ACKs 5, 6 und 8 verloren. Der Sender kann jetzt, wenn er das ACK 7 empfängt, nicht nur das Paket 7 aus seiner Retransmit-Liste entfernen, sondern auch die Pakete 5 und 6, da er weiss, dass der Empfänger nur dann das ACK 7 senden würde, wenn er 5 und 6 schon erfolgreich empfangen hat. Der Sender muss also nur das Paket 8 erneut senden. Andreas
Danke für die Infos, ich werde mal versuchen, etwas draus zu machen. Sequenznummern klingen vernünftig. Allerdings muss ich die wohl für jeden Clienten einzeln führen, wenn es mehrere an einem Server sind. Was mache ich bei Zähler-Überlauf (z.B. Integer mit 4 Byte)? Aber wenn der Server nach der gleichen Methode zählt, geht es ihm genau so und dann stimmts ja wieder ... Frank
Frank Esselbach schrieb: > Allerdings muss ich die wohl für > jeden Clienten einzeln führen, Sinnvollerweise behandelt ein Server jeden Client logisch getrennt in einer eigenen Session.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.