Chat Server-Client mit RMI

Hallo zusammen

Ich habe ein kleines und einfaches Java Chatprogramm angepasst und würde dieses gerne auf mehreren Rechner laufen lassen. Solange ich die Server und Client Codes im selben Package habe, läuft das Programm wunderbar. Wenn ich aber den Server und den Client aus verschiedenen Packages (auf dem gleichen Rechner) starten möchte erhalte ich folgende Fehlermeldung:

java.lang.ClassCastException: P_Server.ChatServerImpl_Stub cannot be cast to P_Client.ChatServer

Kann mir jemand sagen woran dies liegt, beziehungsweise wie ich den Code anpassen muss, damit es läuft?

Meine Packete heissen:

  • P_Server mit allen Codes
  • P_Client mit den Clientcodes

Mein Quelltext ist unterteilt in:
2 Interfaces (TalkServer_Interface und TalkClient_Interface
2 Classes (TalkServer und TalkClient)

Die Quellcodes sind wie folgt :

Interface: TalkServer_Interface

package P\_Server;

import java.rmi.\*;

public interface TalkServer\_Interface extends Remote
{
 public boolean addClient(TalkClient\_Interface objRef) throws RemoteException;
 public void removeClient(TalkClient\_Interface objRef) throws RemoteException;
 public void sendMessage(String name, String msg)
 throws RemoteException;
}

Klasse: TalkServer

package P\_Server;

 import java.rmi.\*;
 import java.rmi.server.\*;
 import java.util.\*;
 import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

 @SuppressWarnings("serial")
 public class TalkServer extends UnicastRemoteObject implements TalkServer\_Interface
 {
 private ArrayList allClients;

 public TalkServer() throws RemoteException
 {
 allClients = new ArrayList();
 }

 public synchronized boolean addClient(TalkClient\_Interface objRef)
 throws RemoteException
 {
 String name = objRef.getName();
 for(Iterator iter = allClients.iterator(); iter.hasNext():wink:
 {
 TalkClient\_Interface cc = iter.next();
 try
 {
 if(cc.getName().equals(name))
 {
 return false;
 }
 }
 catch(RemoteException exc)
 {
 iter.remove();
 }
 }
 allClients.add(objRef);
 return true;
 }

 public synchronized void removeClient(TalkClient\_Interface objRef)
 throws RemoteException
 {
 allClients.remove(objRef);
 }

 public synchronized void sendMessage(String name, String msg)
 throws RemoteException
 {
 for(Iterator iter = allClients.iterator(); iter.hasNext():wink:
 {
 TalkClient\_Interface cc = iter.next();
 try
 {
 cc.print(name + ": " + msg);
 }
 catch(RemoteException exc)
 {
 iter.remove();
 }
 }
 }

 public static void main(String[] args)
 {
 try
 {
 LocateRegistry.createRegistry(Registry.REGISTRY\_PORT); 

 TalkServer server = new TalkServer();
 Naming.rebind("rmi://192.168.56.1/ChatServer", server);
 }
 catch(Exception e)
 {
 System.out.println(e);
 e.printStackTrace();
 }
 }
 }

Interface: TalkClient_Interface

package P\_Client;

public interface TalkClient\_Interface extends java.rmi.Remote
{
 public String getName() throws java.rmi.RemoteException;
 public void print (String msg) throws java.rmi.RemoteException;
}

Klasse: TalkClient

package P\_Client;

import java.rmi.\*;
import java.rmi.server.UnicastRemoteObject;
import java.io.\*;

@SuppressWarnings("serial")
public class TalkClient extends UnicastRemoteObject implements TalkClient\_Interface
{
 private String name;

 public TalkClient(String n) throws RemoteException
 {
 name = n;
 }

 public String getName() throws RemoteException
 {
 return name;
 }

 public void print(String msg) throws RemoteException
 {
 System.out.println(msg);
 }
}

class TalkClientMain
{
 public static void main(String[] args)
 {
 try
 {
 TalkServer\_Interface server = (TalkServer\_Interface) Naming.lookup("rmi://localhost/ChatServer");
 System.out.println("Kontakt zu Server hergestellt");
 System.out.println("Um dem Chat beitreten und teilnehmen zu können,");
 System.out.println("müssen Sie ein Pseudonym wählen:");
 // Chatteilnehmer müssen für die Teilnahme ein Pseudonym eingeben
 // dieses Pseudonym wird in der Variable 'user' abgelegt.
 String user="";
 {
 try
 {
 BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
 String line="";
 line=input.readLine();
 user=line;
 }
 catch(Exception e)
 {
 System.out.println(e);
 }
 }
 args[1]=user;
 TalkClient client = new TalkClient(args[1]);
 if(server.addClient(client))
 {
 System.out.println("Ende durch Einagbe 'Ende' "+ "oder 'ende'");
 sendInputToServer(server, args[1]);
 server.removeClient(client);
 }
 else
 {
 System.out.println("Es ist schon jemand unter "+ "diesem Namen angemeldet");
 }
 }
 catch(Exception e)
 {
 System.out.println(e);
 }
 System.exit(0);
 }

 private static void sendInputToServer(TalkServer\_Interface server, String name)
 {
 try
 {
 BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
 String line;
 while((line = input.readLine()) != null)
 {
 if(line.equals("ende") || line.equals("Ende"))
 {
 break;
 }
 server.sendMessage(name, line);
 }
 }
 catch(Exception e)
 {
 System.out.println(e);
 }
 }
}

Ich starte das ganze in Eclipse. Zuerst der TalkServer (stellt einen Server unter localhost zur Verfügung). Danach starte ich Clients (stellt eine Verbindung zum Server auf localhost her), der Loginname muss jeweils gewählt werden, wobei mehrere identische Namen nicht möglich sind.

Wie gesagt wenn alles im selben Package ist geht es einwandfrei, aber Starte ich Server und Clients aus verschiedenen Packages erscheint die Meldung: java.lang.ClassCastException: P_Server.TalkServer_Stub cannot be cast to P_Client.TalkServer_Interface

Wäre Euch für jegliche Hilfe und Tipps dankbar. Grüsse
Bruno

Hallo Bruno,

Kann mir jemand sagen woran dies liegt, beziehungsweise wie
ich den Code anpassen muss, damit es läuft?
Wäre Euch für jegliche Hilfe und Tipps dankbar. Grüsse
Bruno

bei mir läuft der Code. Ich habe lediglich den user direkt verwendet und nicht das args-array, denn ich habe den Client ohne Parameter gestartet.

Außerdem habe ich zwei Projekte angelegt:
Client - enthält ausschließlich client package
Server - enthält server-package und client interface
Aus dem Client-Projekt starte ich mehrfach clients und aus dem anderen einen Server.

Gruß, Stephan

ps wenn du das args-array verwendest solltest Du eine Abfrage machen, ob die Parameter gesetzt sind, sonst kommt es zu einer ArrayIndexOutOfBoundsException

Hallo Stephan
Danke Dir… habe es auch noch geschafft und jetzt läuft es schon mal auf dem gleichen Rechner auch aus verschiedenen Packages.

Jetzt habe ich noch ein Problem beim Anwählen von einem anderen Rechner. Das anwählen geht, aber die Kommunikation bricht danach ab, da der Client den Server mit der ‚internen‘ IP 192.168… ansprechen will.

Kennst Du dich in diesen Dingen mit RMI aus?

Grüsse
Bruno

willst Du aus dem Internet darauf zugreifen aus Deinem internen Netz.
So oder so müssen die Firewalls entsprechend konfiguriert sein. Zum Testen kannst Du kurzfristig mal Deine Firewalls abschalten.
Wenn Du aus dem Internet darauf zugreifen willst, müssen zusätzlich Einstellungen am Router vorgenommen werden.
Du musst in Deinem Router einen Port und eine feste IP für Deinen Rechner eintragen. Wenn von außen auf diesen Port zugegriffen wird, leitet der Router anhand einer internen Tabelle die Anfrage weiter. Das ganze nennt sich nat (network address translation).

Gruß, Stephan