PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Java RMI


robobimbo
2009-02-22, 23:32:48
Hallo,

für die FH (Verteilte Komponenten und Middleware) muss ich ein kleines verteiltes Spiel mittels RMI Programmieren.

Prinzipiell versteh ich RMI ja, funktioniert auch nicht schlecht - ein einfacher Chat in beide Richtungen funktioniert auch.

Die Aufgabestellung sieht vor, dass sich die Clients das Spiel untereinander ausmachen, also kein dezidierter Server existiert. Angefangen hab ich klein, einfach mit zwei spielenden Clients, RMI Urls hardcoded usw.

Ich habe mir eine Clientklasse erstellt, die ein Listener Interface (so krieg ich Bescheid über die Züge die der Spieler über die (vorgegebene) GUI macht) sowie ein Callback Interface (Das Spielobjekt selbst soll ja nicht dauernd per RMI herumgeschickt werden) implementiert.

Der Plan ist folgender:
Ein jeder Client registriert (bind/rebing) sich einmal als Server (um gemachte Züge von den anderen Clients zu bekommen), sowie holt sich ein ein paar RMI Referenzen auf die anderen (per lookup)

Das heisst, bekommen ich von der GUI die Nachricht "Zug Erfolgt" so rufe ich die entsprechende Methode auf allen RemoteInterfaces der anderen Clients auf, und die können dann (mittels dem erwähnten Callback) den gemachten Zug auf ihrer GUI wieder darstellen.

Umgekehrt werde ich natürlich von den anderen Clients auch aufgerufen, in dem sie mein Remotinterface benutzen.

Sowie die (glaub ich funktionierende) Theorie, irgendwo in meiner Umsetzung tut sich ein Knopf im Hirn auf, denn so gerne ich die entfernten Interfaces aufrufen würde, irgendwie bleibt mein Aufruf immer lokal....

Das Remote Interface


import java.rmi.Remote;

public interface IRemoteAlcatraz extends Remote {

public void doRemoteMove(Player player, Prisoner prisoner, int rowOrCol, int row, int col, IAlcatrazCallback callback);

// Store some additional Information
public String getPlayerName();
public void setPlayerName(String playerName);
public int getPlayerId();
public void setPlayerId(int playerId);

}


Die Interface Implementierung:

import java.io.Serializable;

public class RemoteAlcatraz implements IRemoteAlcatraz, Serializable {
private String playerName;
private int playerId;

...

// Wir sind von einem entfernten Clienten aufgerufen worden, wir müssen das Spielfeld aktualisieren
// Wir benutzen dazu den Callback um nicht die Alcatraz Klasse serialisieren zu müssen.
@Override
public synchronized void doRemoteMove(Player player, Prisoner prisoner, int rowOrCol, int row, int col, IAlcatrazCallback callback) {
System.out.print("RemoteAlcatraz: "+this.toString()+" "+playerName+" "+playerId+": ");
System.out.println(callback.toString());
callback.doExternalMove(player, prisoner, rowOrCol, row, col);
}
....
}


Die Client-Klasse führt dann alles zusammen, dh. reagiert auf die GUI und ruft die anderen RemoteInterfaces auf


public class AlcatrazClient implements MoveListener, IAlcatrazCallback {

public IAlcatrazCallback callback;
Alcatraz localGame = new Alcatraz();
IRemoteAlcatraz self = null;
IRemoteAlcatraz others[] = new IRemoteAlcatraz[3];

public AlcatrazClient(IRemoteAlcatraz localStub, IRemoteAlcatraz otherGame) {
callback = this;
self = localStub;
others[0] = otherGame;
localGame.init(2, localStub.getPlayerId());
localGame.getPlayer(localStub.getPlayerId()).setName(localStub.getPlayerName());
localGame.getPlayer(otherGame.getPlayerId()).setName(otherGame.getPlayerName());
localGame.showWindow();
localGame.addMoveListener(this);
localGame.start();

}
// Player made a Move - so the GUI calls us about it to give the message to the other clients
@Override
public synchronized void doMove(Player player, Prisoner prisoner, int rowOrCol, int row, int col) {
// Rufe das entfernte Interface auf und sag dem anderen Client was er machen soll
others[0].doRemoteMove(player, prisoner, rowOrCol, row, col, callback);
}
...
// Unser entferntes Interface wurde von einem anderen Spiele-Client aufgerufen weil der einen Zug gemacht hat
// Das Interface ruft den Callback auf
@Override
public synchronized void doExternalMove(Player player, Prisoner prisoner, int rowOrCol, int row, int col) {
localGame.doMove(localGame.getPlayer(player.getId()), localGame.getPrisoner(prisoner.getId()), rowOrCol, row, col);
}

}


Dann habe ich noch zwei Klassen die dann zwei Spiele-Clients abbilden sollen - zum Testen, die Binding und RMI Aufrufe sind jeweils umgekehrt

IRemoteAlcatraz localStub = new RemoteAlcatraz();
Naming.rebind("rmi://localhost/Client1", localStub);
IRemoteAlcatraz otherStub = (IRemoteAlcatraz) Naming.lookup("rmi://localhost/Client2");
localStub.setPlayerName("...");
localStub.setPlayerId(0);
otherStub.setPlayerName("...");
otherStub.setPlayerId(1);
AlcatrazClient client1 = new AlcatrazClient(localStub, otherStub);


d.h. der andere Client mach ein Bind auf Client2 und ein lookup auf Client1

Bin ich einfach blind den Fehler nicht zu sehen, oder geht dieser Ansatz so gar nicht umzusetzen?

Vielen Dank im voraus für Eure Mühe und sorry für den vielen Text zum lesen

Berni
2009-02-23, 00:22:09
Ich sehe irgendwie keine Implementierung des Interface? Das ist einfach 2x das Interface?

robobimbo
2009-02-23, 06:38:45
Huch sorry, falsch reinkopiert :) Ich editiere den ersten Post, danke für den Hinweis



EDIT: ahh, ich bin auch ein dillo, die implementierung des interfaces muss nachtürlich von UnicastRemoteObject erben, dann sieht das ganze gleich ganz anders aus :)

Gast
2009-02-23, 13:35:47
auch die interfaces muessen entsprechend deklariert werden.
wie waer es mit rtfm bevor du sowas postest.

einfach mal eben zig zeilen code zu posten ohne eine ahnung von tuten und blasen ...