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
 

Thallius

Top Contributor
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?
 

gamebreiti

Mitglied
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:

Thallius

Top Contributor
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
 

gamebreiti

Mitglied
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
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
K Wie bekomme ich eine Transition für alle Objekte zum stoppen? Spiele- und Multimedia-Programmierung 1
Kim_Dotcom Objekte synchronisieren Variablen Spiele- und Multimedia-Programmierung 19
K Bewegte Objekte per Mausklick entfernen Spiele- und Multimedia-Programmierung 3
N Helden: Verschiedene Objekte oder konkrete Unterklassen Spiele- und Multimedia-Programmierung 1
J Objekte übereinander lagern Spiele- und Multimedia-Programmierung 1
L JavaFX Objekte bewegen Spiele- und Multimedia-Programmierung 3
Q Mehr objekte darstellen als Pixel vorhanden Spiele- und Multimedia-Programmierung 6
lord239123 Minecraft Nur sichtbare Objekte rendern Spiele- und Multimedia-Programmierung 5
Z Objekte animieren mit Threads Spiele- und Multimedia-Programmierung 4
M Objekte verschwinden durch Explosion Spiele- und Multimedia-Programmierung 2
E [LWJGL] Karusell, mehrere Objekte drehen sich um einen Mittelpunkt Spiele- und Multimedia-Programmierung 31
A LWJGL 3D Objekte Kollision Spiele- und Multimedia-Programmierung 3
A JME3 will Blender/j3o Objekte nicht einladen Spiele- und Multimedia-Programmierung 3
B LWJGL/OpenGL rendert manche Objekte nicht Spiele- und Multimedia-Programmierung 6
T JOGL 2D Objekte drehen rotate Spiele- und Multimedia-Programmierung 4
D Objekte in weiter Entfernung flimmern / flackern Spiele- und Multimedia-Programmierung 2
G 3D-Objekte / Grafiken gesucht Spiele- und Multimedia-Programmierung 6
S Klickbare Objekte im Spiel Spiele- und Multimedia-Programmierung 8
T Java3D: Objekte platzieren und entfernen? Spiele- und Multimedia-Programmierung 7
W Rotation aller Objekte einer 3D-Szene Spiele- und Multimedia-Programmierung 8
L 3D Objekte in Java importieren Spiele- und Multimedia-Programmierung 2
M Java3D Picking - falsche Objekte werden gepickt Spiele- und Multimedia-Programmierung 3
P Erkennen auf welche Objekte gezeigt wird in JoGL Spiele- und Multimedia-Programmierung 6
T Selbst-handelnde Objekte im Client-Server Betrieb Spiele- und Multimedia-Programmierung 9
M Java3D Objekte entfernen und hinzufügen Spiele- und Multimedia-Programmierung 10
aze Java 3d Objekte überdecken 2d Komponenten Spiele- und Multimedia-Programmierung 7
aze Java 3D : 3D Objekte speichern und später wieder einlesen Spiele- und Multimedia-Programmierung 9
D Halbdurchsichtige Objekte Spiele- und Multimedia-Programmierung 17
F zu viele Objekte, Problem mit neuzeichnen. Spiele- und Multimedia-Programmierung 5
M Alle Objekte aus der SimpleUniverse entfernen Spiele- und Multimedia-Programmierung 2
A Mehrere geometrische Objekte in JPanel zeichnen Spiele- und Multimedia-Programmierung 4
B Position der ViewingPlatform und Visueller Objekte setzen Spiele- und Multimedia-Programmierung 3
B Isometrischer KartenEditor mit Animierten Objekte Spiele- und Multimedia-Programmierung 3
J 1x Punktlicht auf 5 Objekte benutzen Spiele- und Multimedia-Programmierung 17
F Maussteuerung-gezeichnete Objekte Spiele- und Multimedia-Programmierung 4
B Objekte zur Laufzeit verändern Spiele- und Multimedia-Programmierung 3
A durch Objekte hindurchzoomen Spiele- und Multimedia-Programmierung 2
S 3D Objekte ohne Java3D darstellen? Spiele- und Multimedia-Programmierung 10
J Zu viele Objekte - OutOfMemoryError Spiele- und Multimedia-Programmierung 3
L Objekte zentrieren Spiele- und Multimedia-Programmierung 2
G zur laufzeit objekte einfügen Spiele- und Multimedia-Programmierung 3
G 2D-Objekte werden nicht vollständig gezeichnet Spiele- und Multimedia-Programmierung 4
conan2 Objekte in richtiger Z-Reihenfolge zeichnen Spiele- und Multimedia-Programmierung 2
A Objekte nacheinander zeitgesteuert rotieren lassen Spiele- und Multimedia-Programmierung 4
H 3D Objekte ausfüllen Spiele- und Multimedia-Programmierung 3
T 3D-Objekte Laden Spiele- und Multimedia-Programmierung 3
D 2D Graphic Objekte in ein JPanel einfügen Spiele- und Multimedia-Programmierung 2
G Zugriff auf einzelne Objekte Spiele- und Multimedia-Programmierung 12
J float wert von Smartphone per Bluetooth empfangen Spiele- und Multimedia-Programmierung 32

Ähnliche Java Themen

Neue Themen


Oben