使用 RMI 时 GUI 上不显示文本

Text doesn't appear on GUI while using RMI

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

My project structure

我的 StartClient class。我创建了一个 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 构造函数中,我使用远程方法 register。

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

现在我们在 ChatServerImpl class 的 REGISTER 方法中。我将客户端添加到客户端的 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 始终为空。 (textReceiver 是客户端对象的attribute/field。)

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 并且它们在一个包中时有效,但是一旦我将它们分离到客户端-服务器中,这个问题就出现了。我如何在它们之间进行通信?服务器端我有一个(不相关的?)ChatClients 列表,即使文本到达也不会影响任何东西。

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

编辑:

ChatClientImpl class

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

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

因此,使扩展UnicastRemoteObject并实现您的ChatClient(假定的)远程接口。如果您在这样做时遇到问题,请解决它们。不要随便乱搞事情。它应该实施Serializable.

注意register()的签名应该是register(ChatClient client)。与ChatClientImplclass无关。 unregister().

同上