Socket OutputStreams senden zu oft

  • Themenstarter Themenstarter SebastianF
  • Beginndatum Beginndatum
S

SebastianF

Gast
Hallo.

Ich schreibe derzeit einen Server über den unter anderem auch gechattet werden können soll. Für jeden Client wird ein neuer Thread gestartet. Jeder Thread besitzt ein eigenes Socket zu seinem Client.
Empfangen und senden funktioniert eigentlich prächtig, wenn da nicht folgendes Problem wäre:
Egal welchen Writer ich benutze, egal ob gepuffert oder nicht, egal ob PrintWriter mit println(), print() oder BufferedWriter mit write(), ich bekomme ein reproduzierbares Problem, dass mein Server meint, etwas nur einmal gesendet zu haben, der Server empfängt es aber mehrfach und zerstückelt.
Ich weiß nicht, wie das kommen kann, denn wie gesagt: jeder Client bekommt ein eigenes Socket in seinem Thread. Kein anderer Client kann da dazwischenfunken. Es gibt auch nur sequentielle Zugriffe auf das Socket.
Zum Senden verwende ich derzeit folgende Methode:
Java:
    private void out(String s)
    {
        s = s + end;
        try
        {
            BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(server.getOutputStream()));
            wr.write(s);
            wr.flush();
        } catch(IOException ioe)
        {
            logError("IOException on socket listen: " + ioe);
        }
        System.out.println("=> " + server.getInetAddress().getHostAddress() + " : " + s);
    }

Ich habe zusätzlich das Problem, dass die Clients kein \r\n oder ähnliches zum terminieren verwenden, sondern die Zeichenfolge "|END|" (deshalb die Stringaddition). println() funktioniert deswegen sowieso nicht und ich kann nicht write(x + "\n") ausführen.

Mein Server meint gesendet zu haben:
<= 127.0.0.1 : SHELL|END|
=> 127.0.0.1 : SHELL|END|
<= 127.0.0.1 : SVERS 1.0.1.0|END|
=> 127.0.0.1 : SVERS 1.2.1.0|END|
<= 127.0.0.1 : SCODE test2@mail.com 1a1dc91c907325c69271ddf0c944bc72|END|
=> 127.0.0.1 : SCODE OK|END|
<= 127.0.0.1 : SNICK ONL|END|
=> 127.0.0.1 : SNICK 72 Dummy 0|END|
=> 127.0.0.1 : SLIST 71 ONL Dummy|END|

Der Client empfängt:
C->S: SHELL|END|
C<-S: SHELL|END|
verarbeite: SHELL
C->S: SVERS 1.0.1.0|END|
C<-S: SVERS 1.2.1.0|END|
verarbeite: SVERS 1.2.1.0
Aktuell verfügbare Version ist: 1.2.1.0
C->S: SCODE test2@mail.com 1a1dc91c907325c69271ddf0c944bc72|END|
C<-S: SCODE OK|END|
verarbeite: SCODE OK
C->S: SNICK ONL|END|
C<-S: SLIST 71 ONL Dummy|EN
C<-S: SLIST 71 ONL Dummy|END|
verarbeite: SLIST 71 ONL Dummy|ENSLIST 71 ONL Dummy

Wieso? Es wird nur ein paar mal hintereinander das out-Kommando aufgerufen. Wobei ab SNICK eine Funktion die Ausgabe von SLIST übernimmt. Lagert Java diese etwa in einen neuen Thread aus?

Vielen Dank schonmal für eure Hilfe.
 
Der Code scheint ok so zu sein, wobei ich mir nicht immer einen neuen BufferedWriter erstellen würde sondern nur einmal am Anfang.

Ich vermute ehr der Fehler liegt am Client. Zeig doch da mal den Code wie du empfängst und was du ausgibst.
 
Zuletzt bearbeitet:
Der Code scheint ok so zu sein, wobei ich mir nicht immer einen neuen BufferedWriter erstellen würde sondern nur einmal am Anfang.
jap ... der dürfte spätestens beim Schließen des Socket-Streams von der Bildfläche verschwinden ... bis dahin sollten die ganzen Instanzen Resourcen verschwenden ... ob der auch schon geschlossen wird wenn der BufferWriter geschlossen (wie beim .NET_Framework) weis ich nicht

hand, mogel
 
Hallo.

Der Client ist in C# geschrieben, direkt nach den Informationen der MSDN über TCP-Klassen.

Wir werden jetzt, um den Fehler einzugrenzen, ein paar VMs aufsetzen, den Traffic abhören und dabei versuchen den Fehler zu reproduzieren. Dann sehen wir erstmal, ob ich falsch sende oder der Client falsch empfängt.

Ich sollte noch dazu sagen: es handelt sich nachgewiesen um ein Timingproblem. Übers Internet konnte der Fehler bisher nicht reproduziert werden, vermutlich wegen der langen Laufzeit der Pakete. Ein kurzer Sleep nach jedem out() behebt ebenfalls das Problem. Ich stelle aber nicht gern Eimer unter tropfende Dächer, sondern behebe lieber den Fehler.
 
Der Server sendet
=> 127.0.0.1 : SNICK 72 Dummy 0|END|
=> 127.0.0.1 : SLIST 71 ONL Dummy|END|

und der Client "empfängt"
C<-S: SLIST 71 ONL Dummy|EN <<<=== ???:L
C<-S: SLIST 71 ONL Dummy|END|

Ich kann mir vorstellen, dass der Client die 2. letzte Zeile kriegt, dann die Ausgabe auf die Konsole einleitet (notify? anderer Thread?), und wenn die Ausgabe der 2.letzten Zeile erfolgen sollte, dann ist im Buffer bereits ein grosser Teil der letzten Zeile

Gruss, Rene
 
Hiho.

Der Fehler lag tatsächlich nicht im Java-Server.
Obwohl der Code, den der C#-Client zum Empfangen von Daten verwendet (mit sehr vielen AsyncCallbacks) "in-the-wild" tausendfach eingesetzt wird, zeigt er die eben hier auftretende Schwäche. Keine Ahnung, warum das noch niemand bemerkt hat.
Der Code wurde ersetzt durch eine blockende, synchrone Variante ersetzt - das fällt beim Client bei den paar ms für den Empfang nicht auf. Nun wird alles korrekt empfangen.
 
Obwohl der Code, den der C#-Client zum Empfangen von Daten verwendet (mit sehr vielen AsyncCallbacks) "in-the-wild" tausendfach eingesetzt wird, zeigt er die eben hier auftretende Schwäche.
ich konnte die AsyncCallbacks noch nie leiden - auch nie verwendet

Der Code wurde ersetzt durch eine blockende, synchrone Variante ersetzt - das fällt beim Client bei den paar ms für den Empfang nicht auf. Nun wird alles korrekt empfangen.
dann schiebt das in einen Thread und macht ein Event wenn der Datensatz vollständig angekommen ist

hand, mogel
 

Neue Themen


Zurück
Oben