Rmi, RMI basierter Client / Server Chat

Re: Rmi

hi, ich habe einen Chat programm geschrieben ,
ich habe einen client und einen Server.
der Client und der Server sollen miteinander chätten.
ich weiss jetzt nicht wie ich es schaffe...dass wenn der Client in seinem JTextField was schreibt, es auf dem Gui des Servers taucht.
vielleicht hast du ja eine idee?
 
Re: Rmi

Hallo!

Okay hier nun mal wie gewünscht eine kleine RMI basierte Chat Anwendung:
(Funktioniert so (wegen "Stubless" RMI nur unter Java 5)

Unser ChatServer Interface:
Code:
  /**
   * 
   */
  package de.tutorials;
  
  import java.rmi.Remote;
  import java.rmi.RemoteException;
  
  
  /**
   * @author Tom
   * 
   */
  public interface IChatServer extends Remote {
  	
  	final static String BIND_NAME = "ChatServer";
  	
  	void clientConnect(String clientName, IMessageCallback listener)
  			throws RemoteException;
  
  	void clientDisconnect(String clientName) throws RemoteException;
  
  	int getClientCount() throws RemoteException;
  
  	void publishMessage(String message) throws RemoteException;
  }

Unsere ChatServer Implementierung:
Code:
  /**
   * 
   */
  package de.tutorials;
  
  import java.rmi.RemoteException;
  import java.rmi.registry.LocateRegistry;
  import java.rmi.registry.Registry;
  import java.rmi.server.UnicastRemoteObject;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  
  
  /**
   * @author Tom
   * 
   */
  public class ChatServerImpl extends UnicastRemoteObject implements IChatServer {
  
  	Map<String,IMessageCallback> clients;
  
  	protected ChatServerImpl() throws RemoteException {
  		super();
 		clients = Collections.synchronizedMap(new HashMap<String,IMessageCallback>());
  		System.out.println("Server started!");
  	}
  
  	public void clientDisconnect(String clientName) throws RemoteException {
  		clients.remove(clientName);
  		System.out.println(clientName + " disconnected!");
  	}
  
  	public int getClientCount() throws RemoteException {
  		return clients.size();
  	}
  
  	public void clientConnect(String clientName, IMessageCallback messageCallback)
  			throws RemoteException {
  		if (clients.containsKey(clientName)) {
  			throw new RemoteException("Client " + clientName
 					+ " already connected");
  		}else{
  			clients.put(clientName,messageCallback);
  			System.out.println(clientName + " connected!");
  		}
  	}
  
  	public synchronized void publishMessage(String message) throws RemoteException {
  		System.out.println("publishing message: " + message);
 		for (Iterator<IMessageCallback> iter = clients.values().iterator(); iter.hasNext();) {
  			IMessageCallback messageCallback = iter.next();
  			messageCallback.onMessage(message);
  		}
  	}
  
  	/**
  	 * @param args
  	 */
  	public static void main(String[] args) throws Exception {
  		Registry registry = LocateRegistry.getRegistry();
  		IChatServer chatServer = new ChatServerImpl();
  		registry.bind(IChatServer.BIND_NAME,chatServer);
  	}
  }

Unser ChatClient:
Code:
  /**
   * 
   */
  package de.tutorials;
  
  import java.awt.BorderLayout;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.rmi.RemoteException;
  import java.rmi.registry.LocateRegistry;
  import java.rmi.registry.Registry;
  
  import javax.swing.JButton;
  import javax.swing.JFrame;
  import javax.swing.JTextArea;
  import javax.swing.JTextField;
  import javax.swing.SwingUtilities;
  
  /**
   * @author Tom
   * 
   */
  public class ChatClient extends JFrame {
  
  	JTextArea textArea;
  
  	JTextField textField;
  
  	JButton button;
  
  	IChatServer chatServer;
  
  	IMessageCallback messageCallback;
  
  	String nickname;
  
  	public ChatClient(final String nickname) {
  		super("ChatClient: " + nickname);
  		setDefaultCloseOperation(EXIT_ON_CLOSE);
  
  		this.nickname = nickname;
  
  		textArea = new JTextArea(10, 45);
  		textArea.setEditable(false);
  		textField = new JTextField(45);
  		button = new JButton("send");
  		button.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent e) {
  				try {
  		    	    chatServer.publishMessage(nickname + ": "
 		 		 	+ textField.getText());
  				} catch (RemoteException e1) {
 					e1.printStackTrace();
  				}
  				textField.setText("");
  			};
  		});
  
  		add(textArea, BorderLayout.NORTH);
  		add(textField, BorderLayout.CENTER);
  		add(button, BorderLayout.EAST);
  
  		try {
  			messageCallback = new MessageCallbackImpl(this);
  		} catch (RemoteException e2) {
  			e2.printStackTrace();
  		}
  
  		chatServer = lookupChatServer();
  		try {
  			chatServer.clientConnect(nickname, messageCallback);
  		} catch (RemoteException e1) {
  			e1.printStackTrace();
  		}
  
  		Runtime.getRuntime().addShutdownHook(new Thread() {
  			public void run() {
  				try {
 					messageCallback.shutdown();
  		    	    chatServer.clientDisconnect(getNickname());
  				} catch (RemoteException e) {
 					e.printStackTrace();
  				}
  			}
  		});
  
  		pack();
  		setVisible(true);
  	}
  
  	public void onMessage(final String message) {
  		System.out.println("Recived Message: " + message);
  		SwingUtilities.invokeLater(new Runnable() {
  			public void run() {
 				textArea.append(message + "\n");
  			}
  		});
  	}
  
  	private IChatServer lookupChatServer() {
  
  		try {
  			Registry registry = LocateRegistry.getRegistry();
 			return (IChatServer) registry.lookup(IChatServer.BIND_NAME);
  		} catch (Exception e) {
  			e.printStackTrace();
  		}
  		return null;
  	}
  
  	public String getNickname() {
  		return nickname;
  	}
  
  	public void setNickname(String nickname) {
  		this.nickname = nickname;
  	}
  
  	/**
  	 * @param args
  	 */
  	public static void main(String[] args) {
  		new ChatClient(args[0]);
  	}
  }

Zur Kommunikation von Server zum Client brauchen wir einen Callback Mechanismus -> MessageCallback:

Unser MessageCallback interface:
Code:
  /**
   * 
   */
  package de.tutorials;
  
  import java.rmi.Remote;
  import java.rmi.RemoteException;
  
  public interface IMessageCallback extends Remote{
  	final static String BIND_NAME_PREFIX ="MessageCallback";
  	void onMessage(String message) throws RemoteException;
  	void setBindName(String bindName) throws RemoteException;
  	String getBindName() throws RemoteException;
  	void shutdown() throws RemoteException;
  }

Unsere MessageCallback implementierung:
Code:
  /**
   * 
   */
  package de.tutorials;
  
  import java.rmi.AlreadyBoundException;
  import java.rmi.RemoteException;
  import java.rmi.registry.LocateRegistry;
  import java.rmi.registry.Registry;
  import java.rmi.server.UnicastRemoteObject;
  
  public class MessageCallbackImpl extends UnicastRemoteObject implements
  		IMessageCallback {
  
  	ChatClient chatClient;
  
  	String bindName;
  
  	transient Registry registry = LocateRegistry.getRegistry();
  
  	protected MessageCallbackImpl(ChatClient chatClient) throws RemoteException {
  		super();
  		this.chatClient = chatClient;
  
  		this.bindName = IMessageCallback.BIND_NAME_PREFIX + "_"
  				+ chatClient.getNickname();
  		try {
  			registry.bind(bindName, this);
  		} catch (AlreadyBoundException e) {
 			throw new RemoteException("Could not bind MessageCallback", e);
  		}
  	}
  
  	public void onMessage(String message) throws RemoteException {
  		chatClient.onMessage(message);
  	}
  
  	public String getBindName()  throws RemoteException{
  		return bindName;
  	}
  
  	public void setBindName(String bindName) throws RemoteException{
  		this.bindName = bindName;
  	}
  
  	public void shutdown()  throws RemoteException {
  		try {
  			System.out.println("Shutting down MessageCallback: "
 					+ this.bindName);
  			registry.unbind(bindName);
  			UnicastRemoteObject.unexportObject(this, true);
  		} catch (Exception e) {
  			e.printStackTrace();
  		}
  	}
  }

Um das ganze nun einmal auszuprobieren, müssen wir zuerst die rmiregistry starten:
Code:
 rmiregistry -J-Djava.class.path=E:\eclipse\3.1.1\eclipse\workspace\de.tutorials.training\bin -J-Djava.rmi.server.hostname=192.168.76.98
Mit dem Parameter -J-Djava.class.path gibt man on wie die RMI Registry die Klassen findet. Den Parameter -J-Djava.rmi.server.hostname brauche ich weil ich zwei Netzwerkkarten habe, damit binde ich die RMIRegistry an das Network-Interface mit der IP 192.168.76.98

Anschließend starten wir den ChatServer:
Code:
  E:\eclipse\3.1.1\eclipse\workspace\de.tutorials.training\bin>start java de.tutorials.ChatServerImpl

Anschließend starten wir ein paar Clients:
Code:
 E:\eclipse\3.1.1\eclipse\workspace\de.tutorials.training\bin>for /L %i in (1,1,4) do start java de.tutorials.ChatClient User%i

Beispielausgabe auf dem Server:
Code:
  Server started!
  User4 connected!
  User3 connected!
  User1 connected!
  User2 connected!
  publishing message: User2: hallo welt
  publishing message: User4: tutorials.de -user helfen usern-
  User1 disconnected!
  publishing message: User4: java rocks :)
  User4 disconnected!
  User2 disconnected!
  User3 disconnected!

HTH,

Gruß Tom
 
Hallo,

hier mal noch eine kleineres Beispiel für einen RMI basierten Chat:

ChatClient:
Java:
package de.tutorials.chat;

import java.io.Serializable;
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ChatClient extends Remote, Serializable {
    final static int CHAT_SERVER_PORT = Integer.getInteger("chatServer.port",4711);
    final static String CHAT_SERVER_NAME = System.getProperty("chatServer.name","ChatServer");
    String getName() throws RemoteException;
    void receiveMessage(ChatClient client, String message) throws RemoteException;
}

ChatServer
Java:
package de.tutorials.chat;

import java.rmi.RemoteException;

public interface ChatServer extends ChatClient {
    void connect(ChatClient client) throws RemoteException;
    void disconnect(ChatClient client) throws RemoteException;
}

ChatServer Implementierung
Java:
package de.tutorials.chat;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class Server extends Client implements ChatServer {

    Map<String, ChatClient> clients = new ConcurrentHashMap<String, ChatClient>();
    
    public Server() {
        super("ChatServer");
    }

    public static void main(String[] args) throws Exception {
        ChatServer chatServer = new Server();
        Registry registry = LocateRegistry.createRegistry(CHAT_SERVER_PORT);
        registry.bind(CHAT_SERVER_NAME, UnicastRemoteObject.exportObject(chatServer, 0));
        System.out.println("Server ready...");
        TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
    }

    public void connect(ChatClient client) throws RemoteException {
        clients.put(client.getName(), client);
        super.receiveMessage(this, "Client connected: " + client.getName());
    }

    public void disconnect(ChatClient client) throws RemoteException {
        clients.remove(client.getName());
        super.receiveMessage(this, "Client disconnected: " + client.getName());
    }

    public void receiveMessage(ChatClient client, String message) throws RemoteException {
        super.receiveMessage(client, message);
        for (Map.Entry<String, ChatClient> chatClientEntry : clients.entrySet()) {
            String clientName = chatClientEntry.getKey();
            if (!clientName.equals(client.getName())) {
                ChatClient chatClient = chatClientEntry.getValue();
                chatClient.receiveMessage(client, message);
            }
        }
    }
}

ChatClient Implementierung:
Java:
package de.tutorials.chat;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class Client implements ChatClient {

    String name;

    public Client(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void receiveMessage(ChatClient client, String message) throws RemoteException {
        SimpleDateFormat format = new SimpleDateFormat("hh:MM:ss");
        System.out.printf("[%s] %s: %s\n", format.format(new Date()), client.getName(), message);
    }

    public static void main(String[] args) throws Exception {
        Registry registry = LocateRegistry.getRegistry(CHAT_SERVER_PORT);
        String clientName = System.getProperty("chatClient.name","Client " + System.currentTimeMillis());
        Client client = new Client(clientName);
        
        ChatClient chatClient = (ChatClient) UnicastRemoteObject.exportObject(client, 0);
        ChatServer chatServer = (ChatServer) registry.lookup(CHAT_SERVER_NAME);
        chatServer.connect(chatClient);

        Scanner scanner = new Scanner(System.in);
        
        while (true) {
            String line = scanner.nextLine();

            if (line.trim().equalsIgnoreCase("exit")) {
                chatServer.disconnect(chatClient);
                System.out.println("Bye bye...");
                break;
            } else {
                chatServer.receiveMessage(chatClient, line);
            }
        }
        
        UnicastRemoteObject.unexportObject(client, true);
    }
}

Starten des Servers mit 5 Test-Clients:
Code:
D:\workspaces\sts2.3.3M1\de.tutorials.training>start java -cp bin de.tutorials.chat.Server
D:\workspaces\sts2.3.3M1\de.tutorials.training>for /L %i in (1,1,5) do start java -DchatClient.name=client%i -cp bin de.tutorials.chat.Client

Gruß Tom
 
Zurück