我的目标是制作一个简单的聊天程序。我是RMI的新人。到目前为止我所拥有的是服务器的工作原理。我开始吧然后我启动客户端,它通过RMI将字符串传输到服务器。但它并没有出现在我制作的GUI上。这就是我的问题所在。
我的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);
}
}
答案 0 :(得分:0)
您的ChatClientImpl
类不是导出的远程对象,因此它将被序列化到服务器,并在那里执行。并且因为register()
在构造期间发生,所以在调用setReceiverTextReceiver()
方法之前它将被序列化。因此,相应的字段将为null。在服务器上。这不是你想要的,也不是你想要的。
所以, make 它扩展UnicastRemoteObject
并实现你的ChatClient
(假定的)远程接口。如果您在执行此操作时遇到问题,请解决它们。不要随便乱搞事情。它应该不实施Serializable
。
注意register()
的签名应为register(ChatClient client)
。与ChatClientImpl
类无关。同上unregister()
。