RMI 中的引用传递问题?
有人可以告诉我我错在哪里,为什么这个 RMI 聊天应用程序不起作用,目标是通过远程对象或序列化对象实现客户端、服务器和逻辑之间的解耦。
import javax.swing.*;
import java.awt.event.*;
import java.rmi.*;
import java.rmi.server.*;
public class ChatClient1 implements ICallback {
JFrame frame = new JFrame("Chat Client");
private JTextArea myText;
private static JTextArea TAUinDispMsg;
private JScrollPane myTextScroll;
private JScrollPane TAUinDispMsgScroll;
private String textString = "";
private boolean firstMessage = true;
private static String name = null;
private static final int HOR_SIZE = 400;
private static final int VER_SIZE = 150;
protected static ServerServices chatServer;
MessageImpl remomsg ;
public ChatClient1() throws RemoteException {
super();
try {
this.chatServer = (ServerServices) Naming.lookup("rmi://localhost"
+ "/ChatServer");
UnicastRemoteObject.exportObject(this);
chatServer.register(this);
} catch (Exception e) {
System.err.println("RemoteException: " + e.getMessage());
System.exit(0);
}
;
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
initComponents();
}
});
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
try {
if (name != null) {
// chatServer.leave(displayChat, name);
}
} catch (Exception ex) {
TAUinDispMsg.append("Exit failed.");
}
System.exit(0);
}
});
}
private void initComponents() {
myText = new JTextArea();
myTextScroll = new JScrollPane(myText);
myTextScroll
.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
myTextScroll
.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
myTextScroll.setMaximumSize(new java.awt.Dimension(HOR_SIZE, VER_SIZE));
myTextScroll.setMinimumSize(new java.awt.Dimension(HOR_SIZE, VER_SIZE));
myTextScroll
.setPreferredSize(new java.awt.Dimension(HOR_SIZE, VER_SIZE));
myText.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyTyped(java.awt.event.KeyEvent evt) {
textTyped(evt);
}
});
frame.getContentPane().add(myTextScroll, java.awt.BorderLayout.NORTH);
TAUinDispMsg = new JTextArea();
TAUinDispMsgScroll = new JScrollPane(TAUinDispMsg);
TAUinDispMsg.setBackground(new java.awt.Color(200, 200, 200));
TAUinDispMsgScroll
.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
TAUinDispMsgScroll
.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
TAUinDispMsgScroll.setMaximumSize(new java.awt.Dimension(HOR_SIZE,
VER_SIZE));
TAUinDispMsgScroll.setMinimumSize(new java.awt.Dimension(HOR_SIZE,
VER_SIZE));
TAUinDispMsgScroll.setPreferredSize(new java.awt.Dimension(HOR_SIZE,
VER_SIZE));
TAUinDispMsg.setEditable(false);
frame.getContentPane().add(TAUinDispMsgScroll,
java.awt.BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
private void textTyped(java.awt.event.KeyEvent evt) {
try {
remomsg = new MessageImpl();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
char c = evt.getKeyChar();
if (c == '\n') {
try {
if (firstMessage) {
name = textString;
// .join(name);
firstMessage = false;
} else {
remomsg.sendMessage(name, textString);
}
} catch (RemoteException ie) {
TAUinDispMsg.append("Failed to send message.");
System.err.println(ie.getMessage());
}
textString = "";
} else {
textString = textString + c;
}
}
@Override
public void updateClients(final String msg) throws RemoteException {
// TODO Auto-generated method stub
System.out.println("Recived Message: " + msg);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TAUinDispMsg.append(name + " says: " + msg + "\n");
}
});
}
public static void main(String args[]) throws RemoteException {
ChatClient1 ch = null;
try {
ch = new ChatClient1();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
**ICallback.java: interface for callbacks from server to client**
import java.rmi.*;
public interface ICallback extends Remote {
void updateClients(String msg) throws RemoteException;
}
我想用作业务逻辑(游戏逻辑)的对象。
import java.rmi.*;
public interface Message extends Remote {
public void sendMessage(String name, String message) throws RemoteException;
public void updateClients() throws RemoteException;
}
它的实现:
import java.io.Serializable;
import java.rmi.*;
import java.rmi.server.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class MessageImpl extends UnicastRemoteObject implements Message {
private String name;
private String message;
public MessageImpl() throws RemoteException {
super();
}
public MessageImpl(ArrayList clients2) throws RemoteException {
// TODO Auto-generated constructor stub
this.clients = clients2;
}
static ServerServicesImpl si;
// static ArrayListDemo az;
private List<ICallback> clients = new ArrayList<ICallback>();
// private List<ICallback> clients;
private ServerEngine serverEngine = new ServerEngine();
// Notice this one not called remotely
public void setName(String name) throws RemoteException {
this.name = name;
}
public String getName() {
return name;
}
public void setServerList(ServerEngine serverList2) throws RemoteException {
this.serverEngine = serverList2;
}
public void setClientList(List<ICallback> aclients) throws RemoteException {
this.clients = (ArrayList<ICallback>) aclients;
System.err.println("in setClientlist");
}
public ServerEngine getServerList() {
return serverEngine;
}
// Notice this one not called remotely
public void setMessage(String message) throws RemoteException {
this.message = message;
}
public String getMessage() {
return message;
}
public void updateClients() throws RemoteException {
si = new ServerServicesImpl();
ArrayList j = si.getClientNames();
System.out.println(j.size());
if (clients != null) {
System.out.println(clients.size());
for (ICallback aClient : clients) {
aClient.updateClients(message);
}
} else
System.err.println("Clientlist is empty");
if (clients != null) {
System.out.println(j.size());
} else
System.err.println("Clientlist is empty");
}
public void sendMessage(String name, String message1)
throws RemoteException {
setName(name);
setMessage(message1);
updateClients();
}
}
用于管理客户端线程的类
import java.lang.*;
import java.util.*;
class ServerEngine {
private Collection<ICallback> threadList =
new ArrayList<ICallback>();
private int counter = 0;
// Get the lock on threadList, and wait until the counter is zero - that
//is, no reads are taking place. Then it's safe to add the thread.
public synchronized void add(ICallback item) {
try {
while (counter > 0) {
wait();
}
threadList.add(item);
}
catch (InterruptedException e) {
System.out.println("Addition interrupted.");
}
finally{
notifyAll();
}
}
// Similarly for removal.
public synchronized void remove(ICallback item) {
try {
while (counter > 0) {
wait();
}
threadList.remove(item);
}
catch (InterruptedException e) {
System.out.println("Removal interrupted.");
}
finally {
notifyAll();
}
}
// Similarly for changing counter
public synchronized void incCounter() {
counter++;
notifyAll();
}
public synchronized void decCounter() {
counter--;
notifyAll();
}
//This is because it would be too much effort to make this class implement
//Collection, return it's own Iterator etc. etc...\
//Note it is *not* a bug that it isn't synchronized
public Collection getCollection() {
return threadList;
}
}
Service.java: server 将注册并绑定的对象。
import java.rmi.*;
import java.util.ArrayList;
public interface ServerServices extends Remote {
// added so client can register self with server for callbacks
public void register(ICallback newClient) throws RemoteException;
public ArrayList getClients() throws RemoteException;
}
ServerServicesImpl.java:服务器的实现端
import java.io.Serializable;
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;
class ServerServicesImpl extends UnicastRemoteObject implements ServerServices,
Serializable {
String message;
MessageImpl msgimpl;
static Vector data = new Vector();
private static ArrayList Aclients = new ArrayList<ICallback>();
private static ArrayList testlist;
public ServerServicesImpl() throws RemoteException {
super();
testlist = new ArrayList();
}
public synchronized void register(ICallback newClient)
throws RemoteException {
data.addElement(newClient);
Aclients.add(newClient);
// //serverEngine.add(newClient);
testlist.add("testing");
System.out.println("testlist size =" + testlist.size());
System.out.println(Aclients.size());
setClientList(Aclients);
}
ArrayList getClientNames() {
// Aclients.add(ic);
System.out.println("vector size =" + data.size());
System.out.println("testlist size =" + testlist.size());
System.out.println(" Aclientlist size =" + Aclients.size());
return Aclients;
}
public void setClientList(ArrayList aclients2) {
this.Aclients = aclients2;
}
}
// the server which will publish the above remote object
import java.net.MalformedURLException;
import java.rmi.*;
public class ServiceLoader
{
public static void main(String[] args)
{
try
{
// Install a security manager
System.setSecurityManager(new RMISecurityManager());
ServerServicesImpl obj = new ServerServicesImpl();
Naming.rebind("ChatServer", obj);
System.out.println("ServiceLoader running.");
}
catch (MalformedURLException e)
{
System.err.println(e.getMessage());
}
catch (RemoteException e)
{
System.err.println(e.getMessage());
}
}
}
can somebody please tell me where i m wrong why this RMI chat application not working,the goal is to achieve decoupleing between client, server and logic by remote objects or serialized objects.
import javax.swing.*;
import java.awt.event.*;
import java.rmi.*;
import java.rmi.server.*;
public class ChatClient1 implements ICallback {
JFrame frame = new JFrame("Chat Client");
private JTextArea myText;
private static JTextArea TAUinDispMsg;
private JScrollPane myTextScroll;
private JScrollPane TAUinDispMsgScroll;
private String textString = "";
private boolean firstMessage = true;
private static String name = null;
private static final int HOR_SIZE = 400;
private static final int VER_SIZE = 150;
protected static ServerServices chatServer;
MessageImpl remomsg ;
public ChatClient1() throws RemoteException {
super();
try {
this.chatServer = (ServerServices) Naming.lookup("rmi://localhost"
+ "/ChatServer");
UnicastRemoteObject.exportObject(this);
chatServer.register(this);
} catch (Exception e) {
System.err.println("RemoteException: " + e.getMessage());
System.exit(0);
}
;
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
initComponents();
}
});
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
try {
if (name != null) {
// chatServer.leave(displayChat, name);
}
} catch (Exception ex) {
TAUinDispMsg.append("Exit failed.");
}
System.exit(0);
}
});
}
private void initComponents() {
myText = new JTextArea();
myTextScroll = new JScrollPane(myText);
myTextScroll
.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
myTextScroll
.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
myTextScroll.setMaximumSize(new java.awt.Dimension(HOR_SIZE, VER_SIZE));
myTextScroll.setMinimumSize(new java.awt.Dimension(HOR_SIZE, VER_SIZE));
myTextScroll
.setPreferredSize(new java.awt.Dimension(HOR_SIZE, VER_SIZE));
myText.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyTyped(java.awt.event.KeyEvent evt) {
textTyped(evt);
}
});
frame.getContentPane().add(myTextScroll, java.awt.BorderLayout.NORTH);
TAUinDispMsg = new JTextArea();
TAUinDispMsgScroll = new JScrollPane(TAUinDispMsg);
TAUinDispMsg.setBackground(new java.awt.Color(200, 200, 200));
TAUinDispMsgScroll
.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
TAUinDispMsgScroll
.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
TAUinDispMsgScroll.setMaximumSize(new java.awt.Dimension(HOR_SIZE,
VER_SIZE));
TAUinDispMsgScroll.setMinimumSize(new java.awt.Dimension(HOR_SIZE,
VER_SIZE));
TAUinDispMsgScroll.setPreferredSize(new java.awt.Dimension(HOR_SIZE,
VER_SIZE));
TAUinDispMsg.setEditable(false);
frame.getContentPane().add(TAUinDispMsgScroll,
java.awt.BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
private void textTyped(java.awt.event.KeyEvent evt) {
try {
remomsg = new MessageImpl();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
char c = evt.getKeyChar();
if (c == '\n') {
try {
if (firstMessage) {
name = textString;
// .join(name);
firstMessage = false;
} else {
remomsg.sendMessage(name, textString);
}
} catch (RemoteException ie) {
TAUinDispMsg.append("Failed to send message.");
System.err.println(ie.getMessage());
}
textString = "";
} else {
textString = textString + c;
}
}
@Override
public void updateClients(final String msg) throws RemoteException {
// TODO Auto-generated method stub
System.out.println("Recived Message: " + msg);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TAUinDispMsg.append(name + " says: " + msg + "\n");
}
});
}
public static void main(String args[]) throws RemoteException {
ChatClient1 ch = null;
try {
ch = new ChatClient1();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
**ICallback.java: interface for callbacks from server to client**
import java.rmi.*;
public interface ICallback extends Remote {
void updateClients(String msg) throws RemoteException;
}
The object which i want to serve as business logic (gamelogic).
import java.rmi.*;
public interface Message extends Remote {
public void sendMessage(String name, String message) throws RemoteException;
public void updateClients() throws RemoteException;
}
Its implementation:
import java.io.Serializable;
import java.rmi.*;
import java.rmi.server.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class MessageImpl extends UnicastRemoteObject implements Message {
private String name;
private String message;
public MessageImpl() throws RemoteException {
super();
}
public MessageImpl(ArrayList clients2) throws RemoteException {
// TODO Auto-generated constructor stub
this.clients = clients2;
}
static ServerServicesImpl si;
// static ArrayListDemo az;
private List<ICallback> clients = new ArrayList<ICallback>();
// private List<ICallback> clients;
private ServerEngine serverEngine = new ServerEngine();
// Notice this one not called remotely
public void setName(String name) throws RemoteException {
this.name = name;
}
public String getName() {
return name;
}
public void setServerList(ServerEngine serverList2) throws RemoteException {
this.serverEngine = serverList2;
}
public void setClientList(List<ICallback> aclients) throws RemoteException {
this.clients = (ArrayList<ICallback>) aclients;
System.err.println("in setClientlist");
}
public ServerEngine getServerList() {
return serverEngine;
}
// Notice this one not called remotely
public void setMessage(String message) throws RemoteException {
this.message = message;
}
public String getMessage() {
return message;
}
public void updateClients() throws RemoteException {
si = new ServerServicesImpl();
ArrayList j = si.getClientNames();
System.out.println(j.size());
if (clients != null) {
System.out.println(clients.size());
for (ICallback aClient : clients) {
aClient.updateClients(message);
}
} else
System.err.println("Clientlist is empty");
if (clients != null) {
System.out.println(j.size());
} else
System.err.println("Clientlist is empty");
}
public void sendMessage(String name, String message1)
throws RemoteException {
setName(name);
setMessage(message1);
updateClients();
}
}
class for managaing client threads
import java.lang.*;
import java.util.*;
class ServerEngine {
private Collection<ICallback> threadList =
new ArrayList<ICallback>();
private int counter = 0;
// Get the lock on threadList, and wait until the counter is zero - that
//is, no reads are taking place. Then it's safe to add the thread.
public synchronized void add(ICallback item) {
try {
while (counter > 0) {
wait();
}
threadList.add(item);
}
catch (InterruptedException e) {
System.out.println("Addition interrupted.");
}
finally{
notifyAll();
}
}
// Similarly for removal.
public synchronized void remove(ICallback item) {
try {
while (counter > 0) {
wait();
}
threadList.remove(item);
}
catch (InterruptedException e) {
System.out.println("Removal interrupted.");
}
finally {
notifyAll();
}
}
// Similarly for changing counter
public synchronized void incCounter() {
counter++;
notifyAll();
}
public synchronized void decCounter() {
counter--;
notifyAll();
}
//This is because it would be too much effort to make this class implement
//Collection, return it's own Iterator etc. etc...\
//Note it is *not* a bug that it isn't synchronized
public Collection getCollection() {
return threadList;
}
}
Service.java: server the object which will be register and will bind to.
import java.rmi.*;
import java.util.ArrayList;
public interface ServerServices extends Remote {
// added so client can register self with server for callbacks
public void register(ICallback newClient) throws RemoteException;
public ArrayList getClients() throws RemoteException;
}
ServerServicesImpl.java: implementation side of server
import java.io.Serializable;
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;
class ServerServicesImpl extends UnicastRemoteObject implements ServerServices,
Serializable {
String message;
MessageImpl msgimpl;
static Vector data = new Vector();
private static ArrayList Aclients = new ArrayList<ICallback>();
private static ArrayList testlist;
public ServerServicesImpl() throws RemoteException {
super();
testlist = new ArrayList();
}
public synchronized void register(ICallback newClient)
throws RemoteException {
data.addElement(newClient);
Aclients.add(newClient);
// //serverEngine.add(newClient);
testlist.add("testing");
System.out.println("testlist size =" + testlist.size());
System.out.println(Aclients.size());
setClientList(Aclients);
}
ArrayList getClientNames() {
// Aclients.add(ic);
System.out.println("vector size =" + data.size());
System.out.println("testlist size =" + testlist.size());
System.out.println(" Aclientlist size =" + Aclients.size());
return Aclients;
}
public void setClientList(ArrayList aclients2) {
this.Aclients = aclients2;
}
}
// the server which will publish the above remote object
import java.net.MalformedURLException;
import java.rmi.*;
public class ServiceLoader
{
public static void main(String[] args)
{
try
{
// Install a security manager
System.setSecurityManager(new RMISecurityManager());
ServerServicesImpl obj = new ServerServicesImpl();
Naming.rebind("ChatServer", obj);
System.out.println("ServiceLoader running.");
}
catch (MalformedURLException e)
{
System.err.println(e.getMessage());
}
catch (RemoteException e)
{
System.err.println(e.getMessage());
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
更改
为:
或者在 updateClients() 中的 for() 之前的某处初始化它;
Change
To:
Or initialize it somewhere before the for() in updateClients();
你的问题不够清楚,但是:
调试你的代码,或者在你得到 NPE 的行之前放置一些日志(简单地 System.out.println)。也许你的 List 仍然为空。
your question is not clear enough but:
debug your code, or put some logs (simply System.out.println) before the line that you are getting NPE. maybe you List is still null.
正如Ernest Friedman-Hill在链接中的回答文本http://www .coderanch.com/t/508960/java/java/pass-reference:
问题的根源是RMI不支持按引用传递,因此发出消息类可序列化并在该可序列化类中创建 ServerServices 的远程实例可以使该应用程序工作
,或者
在客户端类中创建 Message 类的远程实例并从 RMI 注册表发布该实例也可以工作。
在此代码中,使用本地引用而不是远程引用,因此它从 Serverservices 类获取列表中的 0 个元素。
再次感谢:欧内斯特·弗里德曼-希尔。
As answered by Ernest Friedman-Hill at link texthttp://www.coderanch.com/t/508960/java/java/pass-reference:
The root of problem was the fact that RMI doesn't support pass by reference , so making the message class serializable and creating the remote instance of ServerServices in that serializable class can make this application work
OR
creating the remote instance of Message class in client class and publishing that from RMI registry can also work.
In this code the local references were used instead of remote, so it was getting the 0 elements in the list from Serverservices class.
thanks again to: Ernest Friedman-Hill.