# Zeitspanne für erneutes senden



## Lord_Aratorn (25. Mai 2010)

Hey, ich habe grade ein ziemliches Loch im Kopf.
Ich habe ein Client-Server System. Sowohl Client als auch Server laufen in ihrem eigenen Thread und übermitteln sich gegenseitig Nachrichten.
Nun Möchte ich sicherstellen, dass ein Packet, wenn es nicht innerhalb einer gewissen Zeitspanne vom Server beantwortet wird, erneut gesendet wird.
Und nun die doofe Frage, wie kann ich dies in der run-Method des Clientthreads realisieren?

Meine idee ist: ich könnte die SystemZeit (System.currentTimeMillis() ) nehmen, wenn der client das packet aussendet. Während jeder Iteration in der run-Method überprüfen, ob Altezeit+Wartezeit < Aktuelle Zeit ist, und wenn dem nicht so ist, abermals das Packet senden.

Ich finde diese Lösung recht unschön und denke, dass es bestimmt eine schönere Möglichkeit gibt, des selben Sachverhalt zu realisieren.


----------



## agentone (25. Mai 2010)

Welches Protokoll verwendest du? TCP oder UDP?

Bei TCP gehen keine Pakete verloren oder verschwinden im Nichts. Das wird automatisch geregelt. Bei UDP allerdings kann es durchaus passieren, dass Pakete verschwinden oder leicht verändert ankommen. Dafür ist der Header von UDP kleiner, man hat also deutlich weniger "Schrott", der "umsonst" mitgeführt wird.


----------



## Lord_Aratorn (25. Mai 2010)

Udp, sonst würde ich nicht fragen


----------



## Michael... (25. Mai 2010)

Lord_Aratorn hat gesagt.:


> Meine idee ist: ich könnte die SystemZeit (System.currentTimeMillis() ) nehmen, wenn der client das packet aussendet. Während jeder Iteration in der run-Method überprüfen, ob Altezeit+Wartezeit < Aktuelle Zeit ist, und wenn dem nicht so ist, abermals das Packet senden.


Wenn mehrere Pakete hintereinander geschickt wurden, wird ja jedesmal die alte Zeit neu gesetzt, wie willst Du dann mitbekommen, dass ein Packet zwischen drin verloren gegangen ist?

Hab zwar nicht viel Ahnung davon, aber ich würde sagen, Du brauchst ein Protokoll mit entsprechendem Header, welcher eine Paket ID enthält, beim versenden speicherst Du diese ID mit dem Paket und der Sendezeit in einer Liste. sobald der Server ein ACK mit der PaketID zurückliefert wird der entsprechende Eintrag aus der Liste gelöscht.
Nebenbei läuft in einem separaten Thread ein Timer der in einem bestimmten Intervall die Zeiten in der Liste kontrolliert, ist ein Paket überfällig wird es mit einer neuen ID versendet und der alte Eintrag gelöscht/überschrieben...
Soweit meine ersten spontanen Überlegungen, hängt na klar davon ab, was und wie Du sendest


----------



## agentone (25. Mai 2010)

Schade, obwohl TCP das Problem lösen würde.
Ich kenne allerdings auch keine andere Lösung für dieses Problem. Allerdings ist deine Formel nicht ganz richtig: Altezeit+Wartezeit < Aktuelle Zeit. 'Wartezeit' soll wohl eher Timeout heißen?
Aber wie sollte man sonst feststellen können, ob das Paket angekommen ist, wenn nicht über das Bestätigen der anderen Seite (Server)? Das ist im echten Leben auch nicht anders!


----------



## Lord_Aratorn (26. Mai 2010)

Der Client soll dafür selbst verantwortlich sein, dass er ein responcePacket erhällt. Es kann natürlich sein, dass dieses responcePacket verschwindet. Dann sollte der Client, da er ja die Zeit weiß, wann er das letzte Packet gesendet hat, dieses Packet erneut aufsetzen. Es soll vermieden werden, dass der Server irgendeine Art von Acknowledge sendet (ich weiß, dass es üblicher Weise so ist  ). Warum? Nun die Kommunikation der Teilnehmer ist verschlüsselt. Falls ein Responce erfolgt, kann ein Attentäter aus dem Inhalt der Responce lesen, ob das Packet verschwunden ist oder ob der Schlüssel nicht angenommen wurde. Mit einem solchen Angriff kann RSA ziemlich schnell geknackt werden. Dies gilt es zu verhindern.


----------



## Michael... (26. Mai 2010)

Lord_Aratorn hat gesagt.:


> Es soll vermieden werden, dass der Server irgendeine Art von Acknowledge sendet


Und woher soll der Client dann wissen, dass das gesendete Paket angekommen ist?


----------



## Foermchen82 (26. Mai 2010)

Den Timestamp kannst du nicht zur Identifikation nutzen, da ggf. auch ein Paket 2 vor einem Paket 1 beim Client ankommen kann. Das ist halt die Natur von UDP. Hier hilft nur eine eigene ID.
Ich würde auch nicht den Server entscheiden lassen ob und wann er etwas sendet oder neu sendet. Der Client muss festellen, dass er einen GAP hat und dann aktiv beim Server nachfragen, dass er alles ab ID X neu braucht.


----------



## Lord_Aratorn (26. Mai 2010)

Michael... hat gesagt.:


> Und woher soll der Client dann wissen, dass das gesendete Paket angekommen ist?


Indem der Client ein bestimmtes Paket erwartet, weil er den Kommunikationsablauf kennt. Der Client soll Faktor*Latenzzeit_zum_Server auf ein solches Paket warten. Wenn kein Paket ankommt, soll das letzte Paket wiederholt gesendet werden.


----------



## Michael... (26. Mai 2010)

Also er sendet ein Paket und wartet auf irgendeine Antwort des Servers und solange er keine Antwort bekommt sendet er nichts weiteres?

Dann kannst Du einfach nach dem Senden einen Timer o.ä. starten. Kommt eine Antwort vom Server wird der Timer abgebrochen und das nächste Paket gesendet, der Timer neu gestarten ...
Läuft der Timer bis zum Ende durch wird das Paket nochmals gesendet und...


----------



## Lord_Aratorn (26. Mai 2010)

ja, so habe ich mir das auch gedacht. Nur gibt es da ein problem. Da das receive ist blockieren. Wenn also auf ein Packet gewartet wird (was es ja wird) arbeitet der Client solange nicht weiter, bis die blockade gelößt wird. Also kann auch erst dann ein neues Packet geschickt werden. Eine Alternative ist es ein nicht blockierendes erhalten zu nutzen, doch das würde die Performance stark beeinträchtigen.


----------



## Michael... (26. Mai 2010)

Das Senden und Empfangen muss in von einander unabhängigen Threads ablaufen.


----------



## Lord_Aratorn (26. Mai 2010)

Ja schon klar, so ist es auch realisiert. Der Server ließt die Pakete vom Stream und schreibt diese in eine LinkedBlockingQueue. Die Hauptverarbeitung dieser Pakete findet in einer weiteren Klasse statt, die die Pakete aus der Queue nimmt und entsprechend bearbeitet und ggf ein Packet sendet (d.h. ein Packet in eine Queue des Clients schreibt).


----------



## Michael... (26. Mai 2010)

Was hat das jetzt mit der BlockingQueue des Servers oder generell mit einer BlockingQueue zu tun?


----------



## Lord_Aratorn (26. Mai 2010)

Ich wollte kurz die Architektur darlegen und erläutern, warum es problematisch ist.


----------



## Michael... (26. Mai 2010)

Meinte nur: Wie Du mit den Paketen weiter verfährst ist ja unabhängig von der Kommunikation zwischen Client und Server.
Das Lesen (im Client) vom InputStream, darf das Senden (im Client) nicht blockieren --> es muss jeweils in einem voneinander unabhängigen Thread passieren.


----------



## Lord_Aratorn (27. Mai 2010)

ja, ich verstehe ja deine Ausführungen. Wenn ich es so betrachte, entspricht die Architektur nicht dem was du beschreibst.
Es existieren zwar pro System jeweils ein client- und ein server-thread, doch agiert die Logik stehts in Abhängigkeit von erhaltenen Paketen. Diese werden wie gesagt von einer blockingQueue des server-threads über ein blockierendes take() abgefragt. Und hier liegt der Knackpunkt. Wenn keine blockierende Methode genutzt würde, könnte unabhängig voneinander gesendet und empfangen werden. Jedoch würde der Logikthread wegen der im run() enthaltenen while-schleife ziemlich viel Performance fressen. Dies gilt es zu vermeiden.


----------

