使用RMI

时间:2016-08-14 22:27:07

标签: java rmi

我的目标是制作一个简单的聊天程序。我是RMI的新人。到目前为止我所拥有的是服务器的工作原理。我开始吧然后我启动客户端,它通过RMI将字符串传输到服务器。但它并没有出现在我制作的GUI上。这就是我的问题所在。

My project structure

我的StartClient类。我创建了一个chatClient,并将chatServer存根作为参数。

public StartClient() throws RemoteException, NotBoundException, MalformedURLException {
    chatServer = (ChatServer) Naming.lookup("rmi://localhost:1099/chatServer");
}

private void run() throws RemoteException, MalformedURLException, NotBoundException {
    ChatClientImpl chatClient1 = new ChatClientImpl(chatServer, "ikke");
    new ChatFrame(chatClient1);

    ChatClientImpl chatClient2 = new ChatClientImpl(chatServer, "bla");
    new ChatFrame(chatClient2);
}

public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException {
    StartClient start = new StartClient();
    start.run();
}

在ChatClientImpl构造函数中,我使用远程方法寄存器。

public ChatClientImpl(ChatServer chatServer, String name) throws MalformedURLException, NotBoundException, RemoteException {
    this.chatServer = chatServer;
    this.name = name;
    chatServer.register(this);
}

现在我们在REGISTER方法中的ChatServerImpl类中。我将客户端添加到客户端的ArrayList。然后我使用方法SENT来显示文本。它调用每个客户端对象具有的RECEIVE方法。

public class ChatServerImpl extends UnicastRemoteObject implements ChatServer {
private List<ChatClient> clients;

public ChatServerImpl() throws RemoteException {
    this.clients = new ArrayList<ChatClient>();
}

public void register(ChatClientImpl client) throws RemoteException {
    clients.add(client);
    send("server", client.getName() + " has entered the room");
}

public void unregister(ChatClientImpl client) throws RemoteException {
    clients.remove(client);
    send("server", client.getName() + " has left the room");
}

public void send(String name, String message) throws RemoteException {
    for(ChatClient client : clients) {
        client.receive(name + ": " + message);
    }
}
}

这是出问题的地方。 textReceiver始终为null。 (textReceiver是客户端对象的属性/字段。)

public void receive(String message) {
    if (textReceiver == null) return;
    textReceiver.receive(message);
}

客户端的ArrayList是服务器端,其中的所有客户端都将textReceivers设置为null。如果你回顾一下StartClient,那就是一条重要的路线。新的ChatFrame(chatClient)。在ChatFrame的构造函数中,我设置了textReceiver。

public ChatFrame(ChatClientImpl chatClient) {
    this.chatClient = chatClient;
    chatClient.setTextReceiver(this);
    String name = chatClient.getName();
    setTitle("Chat: " + name);
    createComponents(name);
    layoutComponents();
    addListeners();
    setSize(300, 300);
    setVisible(true);
}

当我不使用RMI并将它们放在一个软件包中时,此项目有效,但是一旦我将它们分成客户端 - 服务器,就会出现这个问题。我如何在他们之间进行交流?服务器端我有一个(不相关的?)ChatClient列表,即使文本到达也不会影响任何内容。

我是否为每个单独的ChatClient使用RMI并使ChatServer与之连接并发送类似的文本?对我来说似乎很复杂。我该怎么做?

修改

ChatClientImpl类

public class ChatClientImpl implements ChatClient, Serializable {
private ChatServer chatServer;
private TextReceiver textReceiver;
private String name;

public ChatClientImpl(ChatServer chatServer, String name) throws MalformedURLException, NotBoundException, RemoteException {
    this.chatServer = chatServer;
    this.name = name;
    chatServer.register(this);
}

public String getName() {
    return name;
}

public void send(String message) throws RemoteException {
    chatServer.send(name, message);
}

public void receive(String message) {
    if (textReceiver == null) return;
    textReceiver.receive(message);
}

public void setTextReceiver(TextReceiver textReceiver) {
    this.textReceiver = textReceiver;
}

public void unregister() throws RemoteException {
    chatServer.unregister(this);
}
}

1 个答案:

答案 0 :(得分:0)

您的ChatClientImpl类不是导出的远程对象,因此它将被序列化到服务器,并在那里执行。并且因为register()在构造期间发生,所以在调用setReceiverTextReceiver()方法之前它将被序列化。因此,相应的字段将为null。在服务器上。这不是你想要的,也不是你想要的。

所以, make 它扩展UnicastRemoteObject并实现你的ChatClient(假定的)远程接口。如果您在执行此操作时遇到问题,请解决它们。不要随便乱搞事情。它应该实施Serializable

注意register()的签名应为register(ChatClient client)。与ChatClientImpl类无关。同上unregister()