Wie Objekte versenden und empfangen

gamebreiti

Mitglied
Hi Leute,

ich möchte gerne in einem Lan - Kartenspiel zwischen den Clients Nachrichten hin und her schicken um die Spieler und den Kartentisch zu updaten.
Da ein Spieler ziemlich viele Variablen hat und dazu auch Listen gehören möchte ich gern das Spielerobjekt welches diese Variablen hält versenden.
Ich nutze dazu writeObject zum senden und readObject zum empfangen bzw. zum serialisieren und deserialisieren.

Grundgerüst:
Java:
package Net;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;

import javax.swing.SwingUtilities;

import Programm.Gui;
import Programm.Konstanten;
import Programm.Spieler;
import Programm.Startmenu;

public class Client implements Runnable,Konstanten{
  
   public static Gui sb;
  
   private ObjectOutputStream output;
   private ObjectInputStream input;
   private String serverIP;
   private int port;
   private Socket connection;
   public boolean running = false;
   public Spieler localPlayer;
   //Settings
   private int spieleranzahl;
   private ArrayList<NetzwerkSpieler> players ;
   public static boolean offline;
   private ArrayList<String> kartendeck;
   private boolean abenteuer;
   private String nameKartendeck;

   public Client(String host,int port, Spieler localPlayer){
     serverIP = host;
     this.port = port;
     this.localPlayer = localPlayer;
   }
   public void startRunning() {
     try{
       connectToServer();
       setupStreams();
       communicate();
     }catch(EOFException eofex){
       showStatus("Verbindung zum Server verloren");
     }catch (ConnectException connex){
       showStatus("Kein Server online!!!");
       try {
         Thread.sleep(2000);
       } catch (InterruptedException e) {
       }
       showStatus("Versuche es zu einem späteren Zeitpunkt nochmal!!!");
     }catch(IOException ioex){
       ioex.printStackTrace();
     }finally{
       ending();
     }
   }
   private void connectToServer()throws IOException{
     connection = new Socket(InetAddress.getByName(serverIP),port);
     showStatus("Verbindung zu " + connection.getInetAddress().getHostName() + " hergestellt");
   }
   public void setupStreams()throws IOException{
     output = new ObjectOutputStream(connection.getOutputStream());
     output.flush();
     input = new ObjectInputStream(connection.getInputStream());
     //showStatus("Streams sind bereit");
   }
   private void communicate() throws IOException{
     // Vom Server erste Daten empfangen
     try {
       receivce();
     } catch (ClassNotFoundException e) {
     }
    
     do{
       try{
      
         if(offline){
           running = false;
         }
         receivce();
       }
       catch(ClassNotFoundException cnfex){
         System.out.println("unbekanntes Object gesendet");
       }
     }while(running);
    
   }
   private void receivce() throws ClassNotFoundException,IOException{
     Message doThings;
     doThings = (Message)input.readObject();
     checkMessage(doThings);
     System.out.println("Message"+doThings.hashCode());
     System.out.println(input.hashCode());
     System.out.println("Habe Daten vom Server Empfangen");
   }
   private void checkMessage(Message doThings) {
     if(doThings.getType() == JOIN){
       joinGame(doThings);
       send(new Message(JOIN,players.get(localPlayer.getSitzplatz())));
     }
     if(doThings.getType() == SETUP){
       setupGame(doThings);
       createGui();
       matchPlayer(doThings.getPlayer());
      
     }
     if(doThings.getType() == PLAY){
       doThings.getPlayer().getSchritteMAX();
       matchPlayer(doThings.getPlayer());
     }
     if(doThings.getType() == DISCONECT){
      
     }
   }
  private void setupGame(Message doThings) {
     spieleranzahl = doThings.getPlayer().getSpielerListe().size();
     nameKartendeck = doThings.getNameKartendeck();
     kartendeck = doThings.getKartendeck();
     send(new Message(SETUP,players.get(localPlayer.getSitzplatz()),nameKartendeck,kartendeck));
   }
   // Gegener updaten
  
   private void joinGame(Message doThings) {
     /*
      * Spieler der Spielerliste hinzufügen, Position in der Liste
      * setzen und localPlayer updaten, Gesamtspieleranzahl holen
      */
     players = doThings.getPlayer().getSpielerListe();
     players.add(new NetzwerkSpieler(localPlayer));
     spieleranzahl = doThings.getSpieleranzahl();
     localPlayer.setPlayers(players);
     updateSitzplatz(players);
     Startmenu.players = players;
     updateNetplayer(localPlayer);
   }
   private synchronized void createGui() {
     if (spieleranzahl == players.size()){
       updateStartmenu();
       Client.sb = new Gui(this,localPlayer,players,kartendeck,abenteuer);
     }
   }
   private void updateStartmenu() {
     SwingUtilities.invokeLater(new Runnable() {
      
       @Override
       public void run() {
         Startmenu.players = players;
         Startmenu.playerLabel.setText(Integer.toString(players.size()));
         Startmenu.kartenanzahl.setText(Integer.toString(kartendeck.size()));
         Startmenu.deck.setText(nameKartendeck);
       }
     });
   }
private void matchPlayer(NetzwerkSpieler otherPlayer) {
   System.out.println("Der MaxSchritte vom Anderen Spieler sind: " + otherPlayer.getSchritteMAX());
     for(int i = 0; i < players.size();i++){
       if((players.get(i).getName()).equals((otherPlayer).getName())){
         players.remove(i);   // alten Spieler aus SpielerListe entfernen
         players.add(i,otherPlayer); // upgedateten Spieler  an seine Position setzen
         localPlayer.setPlayers(players); // auch bei Local Player austauschen
       }
     }
   }
   private void updateSitzplatz(ArrayList<NetzwerkSpieler> players) {
     NetzwerkSpieler spieler[] = new NetzwerkSpieler[players.size()];
     spieler = players.toArray(new NetzwerkSpieler[players.size()]);
     for(int i = 0; i < spieler.length;i++){
       if(spieler[i].getName().equals(localPlayer.getName())){
         localPlayer.setSitzplatz(i);
         this.players.get(i).setSitzplatz(i);
       }
     }
   }
//   NetPlayerVersion vom Localplayer updaten
  
   public NetzwerkSpieler updateNetplayer(Spieler spieler) {
     NetzwerkSpieler netSp = null;
     for(int i = 0;i < players.size();i++){
       if(spieler.getName().equals(players.get(i).getName())){
         players.get(i).setName(spieler.getName()); //Name setzen
         players.get(i).setSpielerListe(spieler.getPlayers());// Spielerliste setzen
         players.get(i).setNz(spieler.getNz());//Nachziehstapel setzen
         players.get(i).setHand(spieler.getHand());// Handkarten setzen
         players.get(i).setTisch(spieler.getTisch()); //ausgespielte Karten setzen
         players.get(i).setAblage(spieler.getAblage());// Ablage setzen
         if(spieler.getBank().size()>0){
           players.get(i).setTopBankCard(spieler.getBank().get(spieler.getBank().size()-1));// Oberste Bankkarte setzen
         }
         players.get(i).setInfotext(spieler.getInfotext());// Infotext setzen
         players.get(i).setBannreifOffen(spieler.getBannreifOffen());// Bannreif setzen
         players.get(i).setSiegpunkteSp(spieler.getSiegpunkteSp());// Siegpunkte setzen
         players.get(i).setSchritteSp(spieler.getSchritteSp());// Position auf Abenteuerleiste setzen
         players.get(i).setSchritteMAX(spieler.getSchritteMAX());// Länge der Abenteurleiste setzen
         players.get(i).setKraftSp(spieler.getKraftSp());// Aktuelle Kraft setzen
         players.get(i).setKraftMAX(spieler.getKraftMAX());// Max Kraft setzen
         players.get(i).setAnzahlBank(spieler.getBank().size());// Anzahl Bankkarten setzen
         netSp = players.get(i);
       }
     }
     return netSp;
   }
   public void ending(){
     // Meldung an Server senden das ich Verbindung trenne
     send(new Message(DISCONECT,players.get(localPlayer.getSitzplatz())));
     try {
       Thread.sleep(3000);
     } catch (InterruptedException e1) {
     }
     showStatus("Einem Spiel Beitreten...");
    
     try {
       if(connection != null){
       output.close();
       input.close();
       connection.close();
       }
       Startmenu.startButtonVisible(true);
     } catch (IOException e) {
       e.printStackTrace();
     }
   }
   public void send(Message m){
     try{
     output.writeObject(m);
     output.flush();
     }catch(IOException ioex){
       System.out.println("Nachicht konnte nicht gesendet werden");
     }
   }
   // Info anzeigen in der Infobox vom Startmenu
   public static void  showStatus(final String status){
     SwingUtilities.invokeLater(new Runnable() {
       @Override
       public void run() {
         Startmenu.updateInfotext(status, OBEN);
         Startmenu.infoAnzeigen();
       }
     });
   }
   @Override
   public void run() {
     running = true;
     startRunning();
   }
}

Die Message Klasse implementiert Serializable und alle andern involvierten Klassen auch.

Beim Debuggen habe ich nun festgestellt, dass das input Objekt (ObjectInputstream) immer größer wird.
Welches Konzept ist hier richtig, im Netz findet man immer nur Bsp mit Strings z.B. für Chats.
Ist es in diesem Fall besser die Streams und den Socket zu schließen und anschliessend wieder aufzubauen?

In meinen Fall, werden die Änderung im Objekt nicht erkannt
hier die Message Klasse:
Java:
package Net;

import java.io.Serializable;
import java.util.ArrayList;

public class Message implements Serializable{
    /**
     *
     */
    private static final long serialVersionUID = 7228444865879125569L;
    private int type = 0;
    private int spieleranzahl = 0;
    private NetzwerkSpieler player = null;
    private boolean abenteuer = false;
    private String nameKartendeck = null;
    private ArrayList<String> kartendeck = null;
   
    // Konstruktor
    public Message(){
        this.type = 0;
        this.player = null;
        this.nameKartendeck = null;
        this.kartendeck = null;
    }
    public Message(int type, NetzwerkSpieler player,String nameKartendeck, ArrayList<String> kartendeck){
        this.type = type;
        this.player = player;
        this.nameKartendeck = nameKartendeck;
        this.kartendeck = kartendeck;
    }
    public Message(int type, NetzwerkSpieler player,boolean abenteuer){
        this.type = type;
        this.player = player;
        this.abenteuer = abenteuer;
    }
    public Message(int type, NetzwerkSpieler player,int spieleranzahl){
        this.spieleranzahl = spieleranzahl;
        this.type = type;
        this.player = player;
    }
    public Message(int type, NetzwerkSpieler player){
        this.type = type;
        this.player = player;
    }
    public ArrayList<String> getKartendeck() {
        return kartendeck;
    }
    public String getNameKartendeck() {
        return nameKartendeck;
    }
    public int getSpieleranzahl() {
        return spieleranzahl;
    }
    public int getType() {
        return type;
    }
    public NetzwerkSpieler getPlayer() {
        return player;
    }
    public boolean isAbenteuer() {
        return abenteuer;
    }
}

und meine Netzwerkspielerklasse:
Java:
package Net;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import Programm.Card;
import Programm.Spieler;


public class NetzwerkSpieler implements Serializable{
    /**
     *
     */
    private static final long serialVersionUID = -4989598916410873177L;
    private String name = "";
    private ArrayList<NetzwerkSpieler> spielerliste;
    private List<Card> nz = new ArrayList<Card>();
    private List<Card> hand = new ArrayList<Card>();
    private List<Card> tisch = new ArrayList<Card>();
    private List<Card> ablage = new ArrayList<Card>();
    private List<Card> bank = new ArrayList<Card>();
    private Card topBankCard = new Card();
    private boolean bannreifOffen;
    private String infotext = "";
    private int siegpunkteSp = 0;
    private int schritteSp = 0;
    private int schritteMAX = 0;
    private int kraftSp = 0;
    private int kraftMAX = 0;
    private int anzahlBank = 0;
    private int sitzplatz = 0;
    private int kauf = 0;
   
    //     Konstruktor
   
   
    public NetzwerkSpieler(Spieler spieler) {
        super();
        this.ablage = spieler.getAblage();// Ablage setzen
        this.anzahlBank = spieler.getBank().size();// Anzahl Bankkarten setzen
        this.bannreifOffen = spieler.getBannreifOffen();// Bannreif setzen
        this.bank = null;
        this.hand = spieler.getHand();// Handkarten setzen
        this.infotext = spieler.getInfotext();
        this.kauf = spieler.getKauf(); // Kauf setzen
        this.kraftMAX = spieler.getKraftMAX();// Max Kraft setzen
        this.kraftSp = spieler.getKraftSp();// Aktuelle Kraft setzen
        this.name = spieler.getName(); //Name setzen
        this.nz = spieler.getNz();//Nachziehstapel setzen
        this.schritteMAX = spieler.getSchritteMAX();// Länge der Abenteurleiste setzen
        this.schritteSp = spieler.getSchritteSp();// Position auf Abenteuerleiste setzen
        this.siegpunkteSp = spieler.getSiegpunkteSp();// Siegpunkte setzen
        this.sitzplatz = spieler.getSitzplatz(); // Sitzplatz setzen
        this.topBankCard = null;// Oberste Bankkarte setzen
    }
    //GETTER und SETTER
   
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public List<Card> getNz() {return nz;}
    public void setNz(List<Card> nz) {this.nz = nz;}
    public List<Card> getHand() {return hand;}
    public void setHand(List<Card> hand) {this.hand = hand;}
    public List<Card> getAblage() {return ablage;}
    public void setAblage(List<Card> ablage) {this.ablage = ablage;}
    public Card getTopBankCard() {return topBankCard;}
    public void setTopBankCard(Card topBankCard) {this.topBankCard = topBankCard;}
    public List<Card> getBank() {return bank;}
    public void setBank(List<Card> bank) {this.bank = bank;}
    public String getInfotext() {return infotext;}
    public void setInfotext(String infotext) {this.infotext = infotext;}
    public boolean isBannreifOffen() {return bannreifOffen;}
    public void setBannreifOffen(boolean bannreifOffen) {this.bannreifOffen = bannreifOffen;}
    public int getSiegpunkteSp() {return siegpunkteSp;}
    public void setSiegpunkteSp(int siegpunkteSp) {this.siegpunkteSp = siegpunkteSp;}
    public int getSchritteSp() {return schritteSp;}
    public void setSchritteSp(int schritteSp) {this.schritteSp = schritteSp;}
    public int getSchritteMAX() {return schritteMAX;}
    public void setSchritteMAX(int schritteMAX) {this.schritteMAX = schritteMAX;}
    public int getKauf() {return kauf;}
    public void setKauf(int kauf) {this.kauf = kauf;}
    public int getKraftMAX() {return kraftMAX;}
    public void setKraftMAX(int kraftMAX) {this.kraftMAX = kraftMAX;}
    public int getKraftSp() {return kraftSp;}
    public void setKraftSp(int kraftSp) {this.kraftSp = kraftSp;}
    public int getAnzahlBank() {return anzahlBank;}
    public void setAnzahlBank(int anzahlBank) {this.anzahlBank = anzahlBank;}
    public int getSitzplatz() {return sitzplatz;}
    public void setSitzplatz(int sitzplatz) {this.sitzplatz = sitzplatz;}
    public ArrayList<NetzwerkSpieler> getSpielerListe() {return spielerliste;}
    public void setSpielerListe(ArrayList<NetzwerkSpieler> spielerliste) {this.spielerliste = spielerliste;}
    public List<Card> getTisch() {return tisch;}
    public void setTisch(List<Card> tisch) {this.tisch = tisch;}
}

Würde mich über Rat freuen

Gruß gamebreiti
 
Code:
   public NetzwerkSpieler(Spieler spieler){
       super();
       this.ablage= spieler.getAblage();// Ablage setzen
       this.anzahlBank= spieler.getBank().size();// Anzahl Bankkarten setzen
       this.bannreifOffen= spieler.getBannreifOffen();// Bannreif setzen
       this.bank=null;
       this.hand= spieler.getHand();// Handkarten setzen
       this.infotext= spieler.getInfotext();
       this.kauf= spieler.getKauf();// Kauf setzen
       this.kraftMAX= spieler.getKraftMAX();// Max Kraft setzen
       this.kraftSp= spieler.getKraftSp();// Aktuelle Kraft setzen
       this.name= spieler.getName();//Name setzen
       this.nz= spieler.getNz();//Nachziehstapel setzen
       this.schritteMAX= spieler.getSchritteMAX();// Länge der Abenteurleiste setzen
       this.schritteSp= spieler.getSchritteSp();// Position auf Abenteuerleiste setzen
       this.siegpunkteSp= spieler.getSiegpunkteSp();// Siegpunkte setzen
       this.sitzplatz= spieler.getSitzplatz();// Sitzplatz setzen
       this.topBankCard=null;// Oberste Bankkarte setzen
   }

Wozu soill das bitte gut sein? Warum erbt Deine Klasse NetzwerkSpieler nicht einfach von Spieler? Wie willst du das jemals warten wenn ein weiteres Attribut zum Spieler hinzu kommt?
 
Danke der Nachfrage.

Meine Spieler- Klasse ist ziemlich komplex und hat sehr viele Methoden, wollte deshalb eine Klasse welche nur die Variablen hält einbauen. Wenn das aber kein Unterschied macht dann hast du natürlich recht.

Meine Idee ist also, dass das Netzwerkspielerobjekt versendet wird und diese Klasse besitzt außer Getter und Setter überhaupt keine Methoden.

Wenn ich so darüber nachdenke, stellt sich mir die Frage, ob es nicht besser wäre doch das Spielerobjekt zu versenden.

ABER: Kann man auch Methoden transistent machen, sodass sie bei der Serialisierung ausgelassen werden ???????
 
Zuletzt bearbeitet:
Optimieren kann man immer noch wenn es nötig wird. Ich würde erstmal das gesammte Spieler Object versenden.

Weiterihn wäre es super wenn du den Code mal so strukturieren würdest das man nicht erschlagen wird wenn man versucht ihn zu lesen und nur den für den Fehler relevanten Code hier postest. Wie ein Object einer fest definierten Größe von selber größer werden kann erschließt sich mir nicht. Hier wäre eine genaue Fehlerbeschreibung ziemlich sinnvoll.

Gruß

Claus
 
also mein eigentliches Problem ist folgendes.

1. Wenn ein Spieler dem Spiel betritt sendet er eine Nachricht mit einem int type und einem Netzwerkspielerobjekt .... das klappt auch ... also alle anderen Spieler sehen die entsprechenden Werte des Spielers Name , Geld, Siegpunkte etc.
2. wenn dieser Spieler nun aber z.B. eine Karte ausspielt ändert sich ja die Belegung der Attribute (z.B. hat er eine Karte weniger auf der Hand und eine Karte liegt in der Mitte, wieviel Karten darf er noch ausspielen etc.)
Ich bekomme keine Exception aber der Spieler wird nicht upgedatetet. Wenn ich debugge sehe ich dass genau das richtige Netzwerkspielerobjekt (mit den richtigen Werten) in der der writeObjekt - Methode versendet wird, es kommt aber nicht dieses Objekt in der readObjekt an. Die Attribute werden entweder mit null belegt oder halten noch den alten Wert.

Wie läuft das ab?? RMI arbeitet doch mit Reflection, recht es aus wenn ich den Klassen Message und Netzwerkspieler einen NoArg- Konstruktor gebe?????

Größer wird nur das Objeckt input also der Stream (ObjectInputstream), er hat zumindest immer mehr Einträge nach jedem Sendevorgang.
Gruß gambreiti
 

Zurück
Oben