java - java中的RMI聊天程序 - 如何从客户端向客户端发送消息(不通过服务器)?

标签 java client-server rmi

我无法让客户端在不通过服务器的情况下向另一个客户端发送消息。这是一个强制性的学校项目,应该这样实现。如果有人能帮助我,我将不胜感激。

服务器接口(interface):

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");
        }
    }
}

消息接口(interface):

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;   
    }
}

客户端接口(interface):

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();
        }   
    }
}

最佳答案

使用 RMI 实现这一点的唯一方法是客户端也是 RMI 服务器并以某种方式相互发送 stub 。

关于java - java中的RMI聊天程序 - 如何从客户端向客户端发送消息(不通过服务器)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10231588/

相关文章:

java - java中的非法远程方法

java - 从 Parse.com 中的对象 Id 获取数据

java - 读取大型管道分隔值文件时超出 GC 开销限制

java - 为 Google App Engine Java 实现全文搜索的最佳方法是什么

java - 如何使用 CDI(焊接)编写可插拔应用程序?

c# - 在远程机器上运行代码

java - 客户端无法从另一个IP连接

c - linux C 客户端-服务器编程。客户端收不到数据。本地主机

客户端服务器延迟30分钟

java rmi -Djava.rmi.server.hostname=localhost 仍然打开一个监听 0.0.0.0 的套接字