Erste Schritte Server will nicht übergebenes Objekt speichern

ubik

Mitglied
Hallo,

kann mir jemand helfen, bin echt am verzweifeln.

Also ich hab einen Server geschrieben:

Java:
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
    public Server() {
        ServerSocket serversocket = new ServerSocket(9876);
        Counter c = new Counter(50);

        while( true ) {
            Socket socket = serversocket.accept();
            Thread bediener = new ServerHandler(socket, c);
            bediener.start();
          
            System.out.println("Wert " + c.toString());
        }
    }

    public static void main(String[] args) throws Exception {
            Server s = new Server();
    }
}

Java:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.StringTokenizer;
import java.io.StringWriter;




public class ServerHandler extends Thread {
    private Socket so;
    private Counter c;

    public ServerHandler( Socket cs, Counter c) { so = cs; this.c = c; }

    public Counter getCounter() {
        return this.c;
    }

    public void run() {
        try {
            System.out.println(1);
            ObjectInputStream vomClient = new ObjectInputStream( so.getInputStream() );
            StringWriter sw = new StringWriter();
            int c = vomClient.readByte();
            while( c != '\n' ) {
                sw.write( c );
                c = vomClient.readByte();
            }
            String zeile = sw.toString();
            System.out.println(zeile);
            StringTokenizer stok = new StringTokenizer( zeile, " ");
            String objName = stok.nextToken();
            String kommando = stok.nextToken();
                // Feststellen der Objektreferenz zum Objektnamen
            if(kommando.equals("ablegen") ) {
                // Abwickeln des Methodenaufrufs
                Counter counter = (Counter) vomClient.readObject();
                this.c = counter;
                System.out.println(this.c.toString());
                // PrintWriter zumClient = new PrintWriter( so.getOutputStream(), true );
                // zumClient.println("return");
            } else if ( kommando.equals("holen") ) {
                System.out.println("Jetzt holen...");
                ObjectOutputStream zumClient = new ObjectOutputStream( so.getOutputStream() );
                zumClient.writeObject( this.c );
                zumClient.flush();
            } else throw new Exception("Syntaxfehler in Kommando");
            so.close();
        } catch( Exception e) {
            System.out.println("Fehler: " + e );
        }
    }
}

Java:
import java.io.Serializable;

public class Counter implements Serializable {  
    private static final long serialVersionUID = 1L;
    private int count;
  
    Counter() {
        this.count = 0;
    }

    Counter(int z) {
        this.count = z;
    }

    public void incr() {
        this.count++;
    }

    public void decr() {
        this.count--;
    }

    public void resetCounter() {
        this.count = 0;
    }

    public String toString() {
        return String.valueOf(this.count);
    }
}

So. Das ist der Server. Es soll auf dem Server einfach ein Counter-Objekt gespeichert werden, wenn man an den Server "Counter ablegen" schickt. Wenn man an den Server "Counter holen" schickt, dann wird das Counter-Objekt wieder zurückgegeben.

Und hier ist der Client:

Java:
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class CountFrame extends Frame implements Runnable {

    Button bDec = new Button ("<");
    Button bInc = new Button (">");
    Button bQuit = new Button("quit");
    TextField tCounter = new TextField(3);
    Counter c ;
  


    public CountFrame() {
        counterHolen();
    
        tCounter.setEditable(false);
        tCounter.setText(c.toString());      

        // geeignete Beobachter registrieren
        bDec.addActionListener (new ActionListener () {
            public void actionPerformed (ActionEvent e) {
                c.decr();
                tCounter.setText(c.toString());
                counterAblegen();
            }
        });

        bInc.addActionListener (new ActionListener () {
            public void actionPerformed (ActionEvent e) {
                c.incr();
                tCounter.setText(c.toString());
                counterAblegen();
            }
        });

        bQuit.addActionListener (new ActionListener () {
            public void actionPerformed (ActionEvent e) {
                c.resetCounter();
                tCounter.setText(c.toString());
                counterAblegen();
            }
        });

        addWindowListener (new WindowAdapter() {
            public void windowClosing (WindowEvent e) {
                System.exit(0);
            }
        });

        // Komponenten in richtiger Reihenfolge in Panel einfuegen
        Panel p = new Panel(new FlowLayout());
        p.add (bDec);
        p.add (tCounter);
        p.add (bInc);

        // Komponenten in Hauptfenster einfuegen
        add (p, BorderLayout.CENTER);
        add (bQuit, BorderLayout.SOUTH);

        // Fenstergroesse festlegen
        setSize (120, 100);
    }
  
    public void counterHolen() {
            try {  
                Socket so = new Socket( "localhost", 9876 );
              
                ObjectOutputStream zumServer = new ObjectOutputStream( so.getOutputStream());
                zumServer.writeBytes("Counter holen \n");              
                zumServer.flush();
              
                ObjectInputStream vomServer = new ObjectInputStream( so.getInputStream());
                this.c = (Counter) vomServer.readObject();
              
                so.close();
              
            } catch (IOException e2) {
                // TODO Auto-generated catch block
                e2.printStackTrace();
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    }

    public void counterAblegen() {
        try {  
            Socket so = new Socket( "localhost", 9876 );
          
            ObjectOutputStream zumServer = new ObjectOutputStream( so.getOutputStream());
            zumServer.writeBytes("Counter ablegen \n");
            zumServer.writeObject(this.c);
          
            zumServer.flush();
          
            so.close();
          
        } catch (IOException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }
    }

  
    public void run() {
        while(true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            counterHolen();          
        }
    }

    public static void main(String[] args) {
        CountFrame countFrame = new CountFrame();
        countFrame.setVisible(true);
        countFrame.run();
    }
}

Wenn ich jetzt den Button drücke, der den Wert inkrementieren soll, passiert, dass der Server kurz 49 erscheint, aber dann wieder 50... :-( Es soll aber bei 49 bleiben!
 
Zuletzt bearbeitet von einem Moderator:
Das ist Spaghetticode. Solche Sachen wie StringWriter oder StringTokenizer dürfen in einer Client-Server-Architektur-Objekte-senden niemals auftauchen. Das Einzigste (falsch geschrieben, ich weiß), was du brauchst, ist:
clientOutputStream.writeObject(joe);
und
employee = (Employee) serverInputStream.readObject(); ...
Auch gibt's entscheidende Nachteile, entscheidet man sich für diese der Kommunikation. BESSER/aufwändiger/eleganter/sicherer: RMI.
Also lösch' das Ganze wieder, befolge meinen Ratschlag, und fang' noch mal von Scratch an [(ganz) von vorne anfangen].

Desweiteren solltest du überlegen, ob Softwareentwicklung/dein Studiengang wirklich richtige ist. Ich möchte kein Programm einstellen, da so aussieht.
 
Wenn ich jetzt den Button drücke, der den Wert inkrementieren soll, passiert, dass der Server kurz 49 erscheint, aber dann wieder 50... :-( Es soll aber bei 49 bleiben!
Ich glaube, es passiert ungefähr folgendes: Wenn dein Client sich mit dem Server verbindet, startet dieser einen Thread mit einem neuen ServerHandler, dem er das Counter-Objekt des Servers übergibt. Es gibt jetzt also zwei Referenzen auf das Counter-Objekt (eines in Server und eines in ServerHandler).
Der Server Handler bekommt dann vom Client ein Counter-Objekt, dass er in derselben Variablen speichert, in der zuvor das vom Server übergebene Counter-Objekt gespeichert war. Die Variable des Servers referenziert aber noch immer das ursprüngliche Counter-Objekt. Es gibt nun also zwei Counter-Objekte (eines in Server mit dem initialen Wert 50, eines im ServerHandler mit dem Wert 49).
Unmittelbar danach ist der ServerHandler fertig und trennt die Verbindung. Der Thread ist beendet und die Counter-Instanz mit dem Wert 49 existiert nicht mehr, wohl aber die Counter-Instanz in Server, die immer noch den ursprünglichen Wert 50 enthält.
Beim nächsten Abholen durch den Client wird wieder ein neuer ServerHandler-Thread erzeugt und das Spiel beginnt von vorne.
 
Und bei dem war der Aufprall zu hart? 😉

Ist doch nur realistisch.

Ich sag es mal ganz Platt, er bekommt ein Objekt vom Server, verändert es, aber "schreibt es nicht zurück". Ist doch klar, beim nächsten Pull geht die Änderung verloren.

Ich bemängele die Aufteilung der Architektur seiner Anwendung. Ist komplett Nonsens.
 

Neue Themen


Zurück
Oben