TCP "verlorene Pakete"

Status
Nicht offen für weitere Antworten.

hdw

Mitglied
Hallo,

vorweg, ich bin neu in Java.

Ich hab im Forum nichts gefunden, wie ich vermeiden kann, dass ich TCP-Nachrichten in meiner Anwendung übersehe.
Klar, in TCP sollte eigentl. nichts verloren gehen, daher vermute ich, der Fehler liegt in meiner Anwedung/Netzwerkaufruf.

Kurz zum Prgramm:
Ich lese vom Heim-Netzwerk von einem anderen PC die an mich geschickten Nachrichten (TCP). Auf den "Sender" der Daten habe ich keine Einfluss.
Die Nachrichten sind kurze Strings, wenige hundert Bytes.
Die Nachrichten, die ich bekomme sind inkrementell, d.h. in jeder Message wird nicht alles uebertragen, sondern nur Differenzen zu den vorangegangenen Werten. Daher darf nichts übersehen werden. Es gibt keine Paketnummern.
Die Netzwerk-Kommunikation erfolgt in einem eigenen Thread, losgeloest v. der eigentl. Anwendung.
Die Leseroutine (s.u.) ist in einer Endlosschleife ohne sleep() eingebettet.

Der Socket ist mit SoTimeout erzeugt:
Java:
...
SocketAddress socketAddr 
   = new InetSocketAddress( nameOrAddress, port );
socket = new Socket();
socket.connect(socketAddr, 1000);  // allow time to connect
// socket = new Socket(nameOrAddress, port);
socket.setSoTimeout(1100); // set socket read timeout
...
inStream    = sock.getInputStream();
outStream   = sock.getOutputStream();
...

Nun habe ich den Verdacht, dass manchmal in (sehr) kurzer Folge 2-3 Nachrichten hintereinander kommen, ich aber nur jew. das letzte in meiner Anwedung lese.
In der Ausgabe des LOGGERs kann ich nachvollziehen, dass manchmal Nachrichten fehlen.
Aber wie komme ich an die fehlenden/übersehenen/verlorenen Nachrichten?
Ich kann leider nicht mal mit Sicherheit behaupten, dass sie überhaupt gesendet wurden ???:L

Aber wie stelle ich sicher, dass ich keine Nachricht übersehe und wie komme ich an die ggf. "übersehenen" Pakete? Hat eine(r) von Euch 'ne Idee?

Hier meine Leseroutine Code in Auszügen.

Java:
  private String readMessage () {
    String dataLine = "";
    try {
      BufferedReader in = new BufferedReader(new InputStreamReader(inStream));
      dataLine = in.readLine();              // blocking read ...
      dataTime = System.currentTimeMillis(); // ... add data time stamp
      if (LOGGER.isTraceEnabled()) {
        LOGGER.trace("readLine(): " + dataLine);
      }
    }
    catch (SocketTimeoutException ste) {
      /* read timed out -> application paused ... */
      LOGGER.trace("SocketTimeoutException from readline(): "+ste.toString());
    }
    catch (IOException ioe) {
      /* read problem */
      LOGGER.warn("IOException from readLine(): "+ioe.toString());
      // FIXME: close socket, inStream, outStream
    }
    finally {
      // FIXME: close logfile
    }
    return dataLine; // return message or empty string
  } /* end readMessage */

Ist meine Implementierung schon im Ansatz falsch?
Wie müsste ich den Code umschreiben, damit ich keine Nachrichten übersehe/überspringe.

Danke und Gruss, Holger
 

hdw

Mitglied
Tja, wenn ich das wüsste...
Der Server (ich vermute Du meinst den Sender) ist ein binäres Programm, ein echtes *.exe.
Sonst haette ich da schon mal reingeschaut oder gar "nachprogrammiert", um zu sehen was tatsächlich gesendet wird.
 

sparrow

Top Contributor
Momemt....
also erstmal: TCP-Pakete müssen nicht nummeriert werden. Das Protokoll sorgt dafür dass alles und in der richtigen Reihenfolge in der Anwendung ankommt.

Du nimmst also Verbindung mit einem fremden Rechner auf.
Vorweg stellt sich also die Frage: Wer "lauscht" auf einen Port um die Verbindung anzunehmen? Dein PC oder der fremde PC?
 

hdw

Mitglied
Bzgl. Nummerierung:
Ich meinte hier nur eine anwendungsspezief. Nummerierung der Nachrichten durch den Sender.
Das Fehlen einzelner Nchtichten war zunächst nur anhand des Zeitstempels der Nachrichten zu erkennen, denn es gibt Nachrichten, die ca. alle 200ms gesendet werden und eine andere Nachrichtenkategorie sollte ca. alle 1000ms kommen. Da die Nachrichten eine kontinuierl. Bewegung beschreiben, sind die Ausfälle dann auch anhand der Nachrichteninhalte erkennbar.

Der andere PC (ich nenne ihn mal Sender) lauscht auf einem Port und erwartet, dass eine Anwendung eine Verbindung mit ihm erstellt und dort anmeldet. Der Verbindungsaufbau funktioniert problemlos. Ich sehe beim Sender im GUI auch, dass mein Programm (der Empfänger) korrekt erkannt wurde und angemeldet ist.

Meine Java-Programm ist der Empfänger, weil er nach dem Verbindungsaufbau nur noch Daten empfängt, aber nichts sendet (ausser einer initialen Anmeldungsnachricht, die vom Sender bestätigt wird).
Danach beginnt der Sender seine Nachrichten an den Empfänger zu senden.

Aus dem was ich bisher weiss, sollte der "Sender" der Server sein, meine Anwendung muesste daher der Client sein.
 

faetzminator

Gesperrter Benutzer
Versuch mal deinen [c]BufferedReader[/c] zu behalten, und von diesem jeweils ein readLine() aufzurufen, statt immer einen neuen zu erstellen.
 

HoaX

Top Contributor
Versuch mal deinen [c]BufferedReader[/c] zu behalten, und von diesem jeweils ein readLine() aufzurufen, statt immer einen neuen zu erstellen.

Da tippe ich auch drauf. Der BufferedReader tut nämlich das was er soll, er puffert/liest Daten auch wenn du sie noch nicht abrufst. Wenn du beim nächsten Aufruf deiner Methode wieder einen neuen erstellst dann verwirfst du damit die bisher gepufferten.
Wenn das Protokoll wirklich auf Strings basiert dann erstelle _einmal_ den BufferedReader. (Und ich würde beim InputStreamReader noch fest das Encoding mit angeben!).
 

hdw

Mitglied
Danke für die Tipps. Ich werd es ausprobieren.
Wird aber wohl 2 Wochen dauern, bis ich wieder weiter machen kann... hab nun Urlaub :D
Bis spaeter wieder!
 

hdw

Mitglied
Treffer, Eure Tipps waren richtig.
Natürlich war die Ursache das laufende Instanziieren eines neuen BufferedReader. Peinlicher Fehler :oops:
Danke!
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen


Oben