2012-04-19 134 views
0

我無法讓客戶端在不通過服務器的情況下向其他客戶端發送消息。這是一個強制性的學校項目,應該這樣實施。如果有人能幫助我,我將不勝感激。Java中的RMI聊天程序 - 如何從客戶端發送消息到客戶端(不通過服務器)?

服務器接口:

import java.rmi.Remote; 
import java.rmi.RemoteException; 
import java.util.ArrayList; 
import java.util.List; 

public interface ChatServerInt extends Remote { 
    public abstract void register(ChatClientInt inClient) throws RemoteException; 
    public abstract ChatClientInt[] getClients() throws RemoteException; 
    public void disconnect(ChatClientInt client) throws RemoteException; 
} 

服務器執行:

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; 

public class ChatServerImp extends UnicastRemoteObject implements ChatServerInt, Runnable { 
    private ChatClientInt[] clientList; 
    int counter = 0; 
    private ArrayList<String> connectedClients; 
    /** 
    * List of all registered remote clients. 
    */ 
    private List<ChatClientInt> clients = null; 

    /** 
    * Construct an instance of the chat server. 
    */ 
    public ChatServerImp() throws RemoteException { 
     // initialise the list of client objects. 
     clients = new ArrayList<ChatClientInt>(); 
     connectedClients = new ArrayList<String>(); 
     clientList = new ChatClientInt[16]; 
    } 

    /** 
    * Register a chat client. 
    */ 
    public void register(ChatClientInt inClient) throws RemoteException { 
     // perform registration. 
     synchronized(clients) 
     { 
      clients.add(inClient); 
      clientList[counter++] = inClient; 
      inClient = new ChatClientImp(); 

      for(int i = 0 ; i < clients.size();i++) { 
       System.out.println(inClient.getName()+ "has joined\n"); 
      } 
     } 
    } 

    /**After registering, each client will request the list of connected users. 
    * Get a list of chat clients. 
    */ 
    public synchronized ChatClientInt[] getClients() throws RemoteException { 
     // generate and return the list 
     return clientList; 
    } 

    public void disconnect(ChatClientInt client) throws RemoteException { 
     for(int i = 0; i < clients.size(); i++) { 
      System.out.println(client.getName() + "" + "has joined \n"); 
     } 
     clients.remove(client); 
    } 

    /** 
    * Generate a random subset. Based on an implementation of D. Knuth's 
    * @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 should 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) { 
      //System.out.println("waiting for client connection....\n"); 
      // sleep for a while 
      try { 
       Thread.sleep(5000); 
       // iterate through all the clients we know. if we can't communicate with the client 
       // then eliminate it else if we can communicate with the client then do nothing. 
       for(int i =0; i < clients.size(); i++) { 
        try { 
         if(clients.get(i).getName()==null) { 
          clients.remove(clients.get(i).getName()); 
          System.out.println("Disconnected clients:\n" + clients.get(i).getName()); 
         } 
        } 
        catch (RemoteException e) {e.printStackTrace();} 
       }   
      } 
      catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    /** 
    * Start the chat server. 
    * @param args 
    */ 
    public static void main(String[] args) throws Exception { 
     //ChatServerInt server; 
     try { 
      String serverName = "rmi://localhost/ChatServer"; 
      // create an instance of the chat server 
      //server = (ChatServerImp) new ChatServerImp(); 

      //Launch the registry - saves invoking it manually 
      java.rmi.registry.LocateRegistry.createRegistry(1099); 

      // register the instance with the RMIRegistry 
      Naming.rebind(serverName, new ChatServerImp()); 

      //Naming.rebind(serverName, server); 

      // create the server thread and start it 
      //Thread t = new Thread(server).start(); 

      System.out.println("Server running.....\n"); 
     } 
     catch(RemoteException ex) { 
      System.out.println("Error binding the server to rmi"); 
     } 
    } 
} 

消息接口:

import java.util.HashSet; 

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

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

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

    /** 
    * Get an ID for a sender of the message 
    * @return 
    */ 
    public abstract String getSource(); 

} 

留言實施:

import java.io.Serializable; 
import java.util.HashSet; 

public class MessageImp implements MessageInt, Serializable { 
    /** 
    * 
    */ 
    private static final long serialVersionUID = -2686034785384409672L; 
    HashSet<ChatClientInt> clientSet = new HashSet<ChatClientInt>(); 

    String messageContent; 
    String messageSource; 

    public MessageImp(String inUser , String inMsg) { 
     messageSource = inUser; 
     messageContent = inMsg; 
    } 

    /** 
    * Add a chat recipient to the list of receivers 
    * @param inClient 
    */ 
    public void addRecipient(ChatClientInt inClient) { 
     synchronized(inClient) { 
      clientSet.add(inClient); 
     } 
    } 

    /** 
    * Get the set of clients that have seen this message 
    * @return 
    */ 
    public HashSet<ChatClientInt> getRecipients() { 
     return clientSet; 
    } 

    /** 
    * Get the message content. 
    * @return 
    */ 
    public String getContent() { 
     return messageContent; 
    } 

    /** 
    * Get an ID for a sender of the message 
    * @return 
    */ 
    public String getSource() { 
     return messageSource; 
    } 
} 

客戶端接口:

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

public interface ChatClientInt extends Remote { 
    /** 
    * Process a newly received message. 
    * 
    * @param inMessage 
    */ 
    public void processMessage(MessageInt inMessage)throws RemoteException; 

    /** 
    * Returns the name of the client. 
    */ 
    public String getName() throws RemoteException; 

    public boolean sendMessage(MessageInt inMessage) throws RemoteException; 

} 

客戶端實現:

import java.io.Serializable; 
import java.net.MalformedURLException; 
import java.rmi.Naming; 
import java.rmi.NotBoundException; 
import java.rmi.RemoteException; 
import java.rmi.server.UnicastRemoteObject; 
import java.util.ArrayList; 
import java.util.HashSet; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Scanner; 

public class ChatClientImp extends UnicastRemoteObject implements ChatClientInt, Runnable { 
    /** 
    * 
    */ 
    private static final long serialVersionUID = 74130345076834009L; 

    private ArrayList <String> eventHistory = new ArrayList<String>(); 

    private HashSet<ChatClientInt> clientSet = new HashSet<ChatClientInt>(); 

    private List<ChatClientInt> clients;// = new ArrayList<ChatClientInt>(); 

    ChatClientInt[] listFromServer = new ChatClientInt[4]; 

    String clientName; 
    String strMessage; 
    MessageInt messageObj; 
    ChatServerInt serverObj; 


    public ChatClientImp() throws RemoteException { 
     super();  
     clients = new ArrayList<ChatClientInt>(); 
    } 

    public void processMessage(MessageInt inMessage) throws RemoteException { 
     System.out.println("message:" + inMessage.getRecipients().toString() + inMessage.getSource() + inMessage.getContent() + "\n");  
    } 


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

    public synchronized boolean sendMessage(MessageInt inMessage) throws RemoteException { 
     boolean success = false;  
     for(int i = 0; i < clients.size(); i++) { 
      clients.get(i).processMessage(inMessage); 
      inMessage.addRecipient(clients.get(i)); 
      success = true; 
     } 
     return success; 
    } 

    public void displayMessage(String displayName, String displayMsg) { 
     Iterator<ChatClientInt> it = clientSet.iterator(); 
     while(it.hasNext()) { 
      System.out.println(displayName + displayMsg + "\n"); 
     }  
    } 

    public void run() { 
     Scanner scanner = new Scanner(System.in); 
     String userName = ""; 
     try { 
      this.serverObj =(ChatServerInt) new ChatServerImp();    
     } catch (RemoteException e) { 
      e.printStackTrace(); 
     } 
     // Keep requesting until a name is submitted that is not already used. 
     // checking for the existence of a name and adding the name 
     // is done while locking the set of names. 
     System.out.println("Please Enter a username\n"); 

     while(true) {   
      userName = scanner.nextLine(); 
      if(userName==null) { 
       return; 
      } 
      clientName = userName; 
      try { 
       serverObj.register(ChatClientImp.this); 
       listFromServer = serverObj.getClients(); 
       clientSet.add(this);  
      } catch (RemoteException e) { 
       e.printStackTrace(); 
      } 

      System.out.println("Hi" + " " + clientName + " " + "enter your message\n"); 
      String msg = scanner.nextLine(); 
      if(msg.equals("exit")) { 
       try { 
        serverObj.disconnect(this); 
        System.exit(0); 
       } 
       catch (RemoteException e) { 
        e.printStackTrace(); 
       } 
      }//end if 

      if((listFromServer.length) > 1) { 
       System.out.println("list from client is" + " " + listFromServer.length + "going to try to send message.....\n"); 
       try { 
        this.messageObj = new MessageImp(userName, msg); 
        boolean result = this.sendMessage(messageObj); 
        if(result) { 
         System.out.print("sending result is:" + result + "\n"); 
        } else { 
         System.out.println("sending was not successful\n"); 
        } 
       } catch (RemoteException e1) { 
        System.out.println("Error tryiing to send message from the Run()\n"); 
       } 
      } else { 
       System.out.println("There is no one else logged on\n"); 
      } 
     } 
    } 

    public static void main(String[] args) throws RemoteException { 
     String serverUrl= "rmi://localhost/ChatServer"; 
     try { 
      ChatServerInt server = (ChatServerInt)Naming.lookup(serverUrl); 
      Thread thread = new Thread(new ChatClientImp()); 
      thread.start(); 
     } catch (MalformedURLException e) { 
      e.printStackTrace(); 
     } catch (NotBoundException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

請幫助我的任何想法。在此先感謝 – Iyemwen 2012-04-19 23:23:18

+1

問題是您的客戶端線程應該使用'main()'方法中查找的服務器,而不是在'run()'方法中實例化一個。 – jtahlborn 2014-10-11 17:25:20

回答

1

,你可以做到這一點與RMI是,如果只有這樣,客戶端也是RMI服務器和sen d以某種方式對彼此存根。

+0

謝謝。客戶都是在rmi服務器上註冊的。我不知道如何傳遞存根或如何將消息從一個客戶端發送到另一個客戶端而不通過服務器 – Iyemwen 2012-04-20 01:31:06

+1

@lyemwen客戶端可以從服務器獲取另一個客戶端的存根。這只是另一種遠程方法。但除非所有的客戶端都在同一個防火牆之後,否則它將無法工作。 – EJP 2014-09-11 01:24:00