2015-04-22 3 views
4

Я создал интерфейсы и реализации для системы Chat Server, Client и Message. Я скомпилировал все файлы Java. Затем я скомпилировал классы реализации, используя rmic для создания заглушек. Я запустил реестр rmi. Я начал реализацию сервера и работает как ожидалось; подтвердив, что он зарегистрировался в RMI, и он возвращает список активных клиентов. теперь я застрял, как, когда я пытаюсь запустить реализацию клиента witht он ниже командыJava RMI - запуск чат-клиента

start java ChatClientImpl 

появляется окно команды на долю секунды и исчезает. Я не знаю, как заставить клиента работать.

У кого-нибудь есть предложения относительно того, как запустить клиент?

Полный код приложения.

Чат Интерфейс клиента

package p; 
    /** 
    * Defines the remote interface to be used by chat clients. A client 
    * implementation must support all of the methods below. 
    */ 
    public interface ChatClient extends java.rmi.Remote { 
     /** 
     * Process a newly received message. 
     * 
     * @param inMessage 
     * @throws java.rmi.RemoteException 
     */ 
     public void processMessage(MessageImpl inMessage) throws  
     java.rmi.RemoteException; 
     /** 
     * Simple empty method which can be called by the server 
     * and other clients to verify that the client is still 
     * operating. 
     * 
     * @throws java.rmi.RemoteException 
     */ 
     public void ping() throws java.rmi.RemoteException; 
     /** 
     * Returns the name of the client. 
     */ 
     public String getName() throws java.rmi.RemoteException; 
    } 

Реализация чат Клиент

package p; 

import java.rmi.Naming; 
import java.rmi.RemoteException; 
import java.rmi.server.UnicastRemoteObject; 
import java.util.ArrayList; 
import java.util.HashSet; 
import java.util.Iterator; 

/** 
* The client implements the ChatClient and the LocalClient interfaces. 
* 
* A chat client is responsible for relaying on a message it has received from the 
* user or from a different peer to all other peers that it knows about. 
* 
* The client should try to reduce the number of pointless relays of the message. 
* Minimally if it has already received the message, it should not pass the message 
* on further. 
*/ 
public class ChatClientImpl extends UnicastRemoteObject implements ChatClient{ 

    private static final long serialVersionUID = 3056117484716596895L; 

    private ChatServer listServer = null; 

    private ArrayList<ChatClient> knownClients = null; 

    private String clientName = null; 

    private ArrayList<GUID> processedMessages = null; 

    private JChatClient gui = null; 

    public ChatClientImpl(String inServerName,       
          String inClientName) throws Exception{ 
     // set the client name 
     this.clientName = inClientName; 

      // connect to chat server through RMI 
     this.listServer = (ChatServer) Naming.lookup(inServerName); 

     // create the empty list of processed messages 
     this.processedMessages = new ArrayList<GUID>(); 

     // register with the ChatServer 
     this.listServer.register(this); 

     // request a set of clients. 
     ChatClient[] newClients = this.listServer.getClients(); 

     // add the new set to our known set. 
     this.knownClients = new ArrayList<ChatClient>(); 
     this.addClients(newClients); 
    } 

    protected void setGUI(JChatClient inGUI){ 
     this.gui = inGUI; 
    } 

    /** 
    * Add a list of clients to our known clients. 
    * 
    * @param inClients 
    */ 
    private void addClients(ChatClient[] inClients){ 
     for(int i = 0; i < inClients.length; i++){ 
      if(!this.knownClients.contains(inClients[i])){ 
       this.knownClients.add(inClients[i]); 
      } 
      else{ 
       System.err.println("already know that peer - will not add."); 
      } 
     } 
    } 

    public void handleMessage(String inString){ 
     // create a message instance 
     MessageImpl msg = new MessageImpl(this,inString); 

     // broadcast to all clients 
     Iterator<ChatClient> i = this.knownClients.iterator(); 
     while(i.hasNext()){ 
      ChatClient knownClient = i.next(); 
      try { 
       knownClient.processMessage(msg);  
      } catch (RemoteException e) { 
       // looks like the client isn't there any longer. 
       i.remove(); 
      } 
     }  
    } 

    /** 
    * Process a newly received message. 
    * 
    * @param inMessage 
    * @throws java.rmi.RemoteException 
    */ 
    public void processMessage(MessageImpl inMessage) throws java.rmi.RemoteException{ 
     System.out.println("message received"); 

     // check the message to see if we have processed it before - discard if so 
     if(this.processedMessages.contains(inMessage.id)) return; 
     else{ 
      System.err.println(inMessage.id); 
      this.processedMessages.add(inMessage.id); 
      System.err.println("have now processed " + this.processedMessages.size()); 
     } 

     // if we have not displayed it, then notify our viewer 
     this.gui.updateDisplay(inMessage);; 

     // get all new known clients from the message 
     HashSet<ChatClient> recipients = inMessage.getRecipients(); 

     // add the names of any new recipients to known list 
     for (ChatClient chatClient : recipients) { 
      if(knownClients.contains(chatClient)){ 
       System.out.println("already know about that client"); 
      } 
      else{ 
       System.out.println("discovered a new recipient"); 
       this.knownClients.add(chatClient); 
      } 
     } 

     // pass the message on to any clients who have not already seen the message 
     Iterator<ChatClient> iter = this.knownClients.iterator(); 
     while(iter.hasNext()){ 
      ChatClient chatClient = iter.next(); 
      if(recipients.contains(chatClient)){ 
       System.err.println("aready sent to that client"); 
      } 
      else{ 
       System.out.println("sending to a new client"); 
       try { 
        chatClient.processMessage(inMessage); 
       } catch (RemoteException e) { 
        // looks like the client isn't there any longer. 
        iter.remove(); 
       } 
      } 
     } 
    } 

    /** 
    * Simple empty method which can be called by the server 
    * and other clients to verify that the client is still 
    * operating. 
    * 
    * @throws java.rmi.RemoteException 
    */ 
    public void ping() throws java.rmi.RemoteException{ 
     /* doesn't have to do anything */ 
    } 

    /** 
    * Get the client name. 
    */ 
    public String getName() throws java.rmi.RemoteException{ 
     return this.clientName; 
    } 
} 

интерфейс Chat Server

package p; 

import java.rmi.Remote; 
import java.rmi.RemoteException; 

public interface ChatServer extends Remote { 

    /** 
    * Register the ChatClient instance with the ChatServer. 
    * @param inClient 
    */ 
    public abstract void register(ChatClient inClient) throws RemoteException; 

    /** 
    * Request a set of clients from the chat server. 
    */ 
    public abstract ChatClient[] getClients() throws RemoteException; 
} 

Внедрение Chat Server

package p; 

import java.rmi.Naming; 
import java.rmi.RemoteException; 
import java.rmi.server.UnicastRemoteObject; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 

/** 
* A chat server allows chat clients to locate other chat clients. 
* The chat server is not used during message broadcast. It is 
* only used when the chat clients initially connect to the chat session. 
* 
* Communication with the server (as with all other modules) will be 
* conducted with RMI rather than a custom TCP or UDP protocol. 
* 
* Each client only communicates with a small set of peers. The 
* ChatServer is responsible for deciding upon the set of peers. 
* 
public class ChatServerImpl extends UnicastRemoteObject implements ChatServer, Runnable{ 

    private static final long serialVersionUID = 1344922080333520010L; 
    private static final int RETURN_SET_SIZE = 3; 
    private static final int PING_SLEEP_DURATION = 60000; 

    /** 
    * Hashtable of all registered remote clients. 
    */ 
    private List<ChatClient> clients = null; 

    /** 
    * Chat server is started once on a server. Students will have to 
    * start an instance themselves. If we were to have a number of 
    * students working together, one server would be started central. 
    */ 
    public ChatServerImpl() throws RemoteException{ 
     this.clients = new ArrayList<ChatClient>(); 
    } 

    /* (non-Javadoc) 
    * @see p.ChatServer#register(p.ChatClient) 
    */ 
    @Override 
    public void register(ChatClient inClient) throws RemoteException{ 
     if(!this.clients.contains(inClient)) this.clients.add(inClient); 
    } 

    /* (non-Javadoc) 
    * @see p.ChatServer#getClients() 
    */ 
    @Override 
    public synchronized ChatClient[] getClients() throws RemoteException{ 
     if(this.clients.size() > RETURN_SET_SIZE){ 
      List<ChatClient> clientSample = randomSample2(this.clients, RETURN_SET_SIZE); 
      return (ChatClient[]) this.clients.toArray(new ChatClient[ this.clients.size() ]); 
     } 
     else return (ChatClient[]) this.clients.toArray(new ChatClient[ this.clients.size() ]); 
    } 

    /** 
    * Generate the random subset. Based on an implementation of D. Knuth's 
    * algorithm. 
    * 
    * @param <T> 
    * @param items 
    * @param m 
    * @return 
    */ 
    private static <T> List<T> randomSample2(List<T> items, int m){ 
     Random rnd = new Random(); 
     for(int i=0;i<items.size();i++){ 
      int pos = i + rnd.nextInt(items.size() - i); 
      T tmp = items.get(pos); 
      items.set(pos, items.get(i)); 
      items.set(i, tmp); 
     } 
     return items.subList(0, m); 
    } 

    /** 
    * Run the server's main thread. The server will periodically 
    * iterate through all registered clients to find out if they 
    * are still alive. Any dead clients will be removed from the 
    * client list. 
    */ 
    public void run(){ 
     while(true){ 
      try {Thread.sleep(PING_SLEEP_DURATION);} catch (Exception e) {} 
      System.out.println("Performing Update"); 
      // we don't want to lock the list, so we will make a copy of it 
      // for the checking phase. 
      ArrayList<ChatClient> copy = new ArrayList<ChatClient>(this.clients); 
      System.out.println("Checking " + copy.size() + " clients"); 
      for (ChatClient chatClient : copy) { 
       try { 
        chatClient.ping(); 
       } catch (RemoteException e) { 
        System.out.println("Removing a client."); 
        // client is no longer accessible. 
        // We will remove the client from the main list 
        this.clients.remove(chatClient); 
       }     
      } 
     } 
    } 

    /** 
    * Start the chat server. 
    * @param args 
    */ 
    public static void main(String[] args) throws Exception{ 
     // create an instance of the chat server 
     ChatServer server = new ChatServerImpl(); 

     // register the instance with the RMIRegistry 
     Naming.rebind("rmi://localhost/chat", server); 
     System.out.println("Registration with RMI complete."); 

     // create the server thread and start it  
     Thread th = new Thread(((ChatServerImpl)server)); 
     th.start(); 
     System.out.println("Server thread now running."); 
    } 
} 

Интерфейс сообщений

package p; 

import java.util.HashSet; 

public interface Message { 

    /** 
    * Add a chat recipient to the list of receivers 
    * @param inClient 
    */ 
    public abstract void addRecipient(ChatClient inClient); 

    /** 
    * Get the set of clients that have seen this message 
    * @return 
    */ 
    public abstract HashSet<ChatClient> getRecipients(); 

    /** 
    * Get the message content. 
    * @return 
    */ 
    public abstract String getContent(); 


    public abstract String getSource(); 
} 

Реализация Сообщение

package p; 

import java.util.HashSet; 

/** 
* Must have some unique identifier. Peer + number. 
*/ 
public class MessageImpl implements java.io.Serializable, Message { 

    /** 
    * Generated versionaID 
    */ 
    private static final long serialVersionUID = 8914588083609635659L; 

    /** 
    * The globally unique identifier for this message 
    */ 
    public final GUID id; 

    /** 
    * All remote clients that this message has passed through, 
    * including source 
    */ 
    public final HashSet<ChatClient> passedThrough = new HashSet<ChatClient>(); 

    /** 
    * The content of the message. 
    */ 
    private String content = null; 

    /** 
    * The client who created the object 
    */ 
    private ChatClient client = null; 

    /** 
    * Create a new Message instance. 
    */ 
    public MessageImpl(ChatClient s, String inContent) { 
     this.id = new GUID(s); 
     this.client = s; 
     this.passedThrough.add(s); 
     this.content = inContent; 
    } 

    /* (non-Javadoc) 
    * @see p.MessageInterface#addRecipient(p.ChatClient) 
    */ 
    @Override 
    public void addRecipient(ChatClient inClient){ 
     this.passedThrough.add(inClient); 
    } 

    /* (non-Javadoc) 
    * @see p.MessageInterface#getRecipients() 
    */ 
    @Override 
    public HashSet<ChatClient> getRecipients(){ 
     return this.passedThrough; 
    } 

    /* (non-Javadoc) 
    * @see p.MessageInterface#getContent() 
    */ 
    @Override 
    public String getContent(){ 
     return this.content; 
    } 

    /** 
    * Get the name of the source of the message 
    * @return 
    */ 
    public String getSource(){ 
     try { 
      return this.client.getName(); 
     } catch (Exception e) { 
      return "client uncreachable"; 
     } 
    } 
} 

    /** 
    * Class used to generate globally unique identifiers for each message. 
    * 
    * The GUID is based on the client plus an increment for each new 
    * message instance. 
    */ 
    class GUID implements java.io.Serializable { 
     /** 
     * Generated versionaID 
     */ 
     static final long serialVersionUID = 4928185858035458591L; 

     /** 
     * Reference to the client -- needed to generate a number. 
     */ 
     public final ChatClient source; 

     /** 
     * Next number that should be used - defined statically 
     */ 
     private static int nextID; 

     /** 
     * The message number to be used in the current GUID 
     */ 
     private int id = 0; 

     /** 
     * Generate a GUID for use by a client. 
     * @param s 
     */ 
     public GUID(ChatClient s) { 
      this.source = s; 
      synchronized(GUID.class) { 
       this.id = nextID++; 
      } 
     } 

      public final int hashCode() { 
       return source.hashCode() + id; 
      } 

      public final boolean equals(Object that) { 
       if (!(that instanceof GUID)) return false; 
       GUID m2 = (GUID)that; 
       return id == m2.id && source.equals(m2.source); 
     } 
    } 

GUI

package p; 

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Toolkit; 
import java.awt.event.ActionEvent; 
import java.io.IOException; 
import java.rmi.RemoteException; 

import javax.swing.BoxLayout; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTextField; 
import javax.swing.JTextPane; 
import javax.swing.text.SimpleAttributeSet; 
import javax.swing.text.StyleConstants; 
import javax.swing.text.StyledDocument; 

public class JChatClient extends JFrame implements java.awt.event.ActionListener{ 

    private ChatClientImpl model = null; 

    /** 
    * Field for users to enter text. 
    */ 
    protected JTextField inputField = null; 

    /** 
    * Text area where user and system text is printed out. 
    */ 
    private JTextPane historyPane = null; 

    /** 
    * 
    * @param name 
    * @param host 
    * @param mname 
    * @throws RemoteException 
    */ 
    public JChatClient(ChatClient inClient, String inUserName) throws RemoteException { 
     super("Chat: " + inUserName); 
     this.model = (ChatClientImpl) inClient; 
     this.model.setGUI(this); 

     super.setLayout(new BorderLayout()); 

     // create the main output panel  
     this.historyPane = new JTextPane(); 
     this.historyPane.setAutoscrolls(true); 
     this.historyPane.setEditable(false);   
     this.historyPane.setPreferredSize(new Dimension(100,100)); 

     // create a scrollpane to put the output panel in. This will then be added to the parent container. 
     JScrollPane historyView = new JScrollPane(historyPane);   
     historyView.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 
     historyView.setAutoscrolls(true); 
     super.add(historyView, BorderLayout.CENTER); 

     // create and add the input field 
     this.inputField = new JTextField("", 20); 
     this.inputField.addActionListener(this); 
     JPanel bottom = new JPanel(); 
     bottom.setLayout(new BoxLayout(bottom,BoxLayout.X_AXIS)); 
     bottom.add(inputField); 
     super.add(bottom, BorderLayout.SOUTH);   

     this.centerAndSetVisible(); 
    } 

    /** 
    * Updates the display with details of a new message. 
    * @param inMessage 
    * @throws IOException 
    */ 
    public void updateDisplay(MessageImpl inMessage) { 
     this.printText("\n" + inMessage.getSource() + ": " + inMessage.getContent(),Color.BLACK); 
    } 

    /** 
    * Called when the 'send' button has been hit. 
    * 
    * Must be extended to update all clients with information on the text that 
    * was entered by the user. 
    */ 
    public void actionPerformed(ActionEvent e) { 
     String msg = inputField.getText(); 
     if (msg.length() > 0) { 
      // Clear the chat input field 
      inputField.setText(""); 

      // update (directly or indirectly) any peers of the message update. 
      this.model.handleMessage(msg); 
     } 
    } 

    /** 
    * Utility method for doing the work of printing a message in a 
    * given colour to the output window. 
    * 
    * @param inText 
    * @param inColor 
    */ 
    private void printText(String inText, Color inColor){ 
     StyledDocument doc = historyPane.getStyledDocument(); 
     SimpleAttributeSet attr = new SimpleAttributeSet(); 
     StyleConstants.setForeground(attr, inColor); 

     try { 
      doc.insertString(doc.getLength(),inText,attr);  
      historyPane.setCaretPosition(doc.getLength()); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     }  
    }   

    /** 
    * Put everything in the right place. 
    */ 
    private void centerAndSetVisible(){ 
     this.pack(); 
     this.setPreferredSize(new Dimension(300, 300)); 
     Dimension labelSize = this.getPreferredSize(); 
     Dimension sd = Toolkit.getDefaultToolkit().getScreenSize(); 
     int x = (sd.width - labelSize.width)/2; 
     int y = (sd.height - labelSize.height)/2; 
     this.setLocation(x, y); 
     setSize(new Dimension(labelSize.width, labelSize.height)); 
     this.setVisible(true); 
     this.setAlwaysOnTop(false); 
    }  

    public static void main(String[] args) throws Exception{ 
     // find address of chat name server 
     ChatClientImpl client = new ChatClientImpl(args[0], args[1]); 
     new JChatClient(client,args[1]); 
    }  
} 
+0

Вероятно, вы получите исключение, когда окно запустится и снова закроется. Попробуйте запустить его только с помощью «java ChatClientImpl» (т. Е. Без «запуска», так как это открывает новое окно консоли) и посмотрите на результат. – mhlz

+1

Где вы основной метод? Я видел только один основной метод в классе ChatServerImpl, но не видел его в классе ChatClientImpl. –

+1

Извините, Евгений, совсем забыл об этом. У меня есть основной метод в графическом интерфейсе. Не уверен, что это вызывает проблему. –

ответ

0
start java ChatClientImpl 

Способ отладки это, чтобы удалить start часть. Когда вы это сделаете, вы увидите исключение из-за отсутствия основного метода. Вы начинаете не тот класс. Основной метод находится в JChatClientImpl.

-1

Наконец понял, что я делаю неправильно. После запуска реестра RMI и запустить сервер я попытался запустить ниже из командной строки:

start java JChatClient rmi://localhost/chat User1 

чат приложение теперь работает. Спасибо за все предложения.

+0

Ты, наконец, осознал это через день после того, как тебе сказали дважды. – EJP