有人可以告诉我这个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:服务器将要注册并绑定到的对象。
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());
}
}
}
正如 Ernest Friedman-Hill
在链接文本
http://www.coderanch.com/t/508960/java/java/pass-
reference上
回答的那样:
问题的根源在于RMI不支持按引用传递,因此使消息类可序列化并在该可序列化类中创建ServerServices的远程实例可以使此应用程序正常工作
要么
在客户端类中创建Message类的远程实例并从RMI注册表中发布它也可以工作。
在此代码中,使用本地引用而不是远程引用,因此它从Serverservices类获取列表中的0元素。
再次感谢: 欧内斯特·弗里德曼·希尔 。
问题内容: 我有以下代码: 有人可以解释为什么输出是:零一二二。 摘自zend认证学习指南。 问题答案: 因为在第二个循环中,仍然是对最后一个数组项的引用,所以每次都将其覆盖。 您可以看到这样的内容: 如您所见,最后一个数组项采用当前循环值:“零”,“一个”,“两个”,然后就是“两个” …:)
问题内容: 这两个代码有什么区别: 代码A: 哪里 VS. 代码B: 这两个代码之间有什么区别吗? 问题答案: Java始终按值传递参数,而不按引用传递参数。 让我通过一个例子解释一下: 我将逐步解释这一点: 声明一个名为ftype 的引用,Foo并将其分配给Foo具有属性的type的新对象”f”。 从方法方面,声明Foo具有名称的类型引用,a并将其初始分配给null。 调用方法时changeRe
问题内容: Go中的地图是否通过值或引用传递? 始终可以将函数定义为以下形式,但这是一个过大的杀伤力吗? 相同的返回值问题。我应该返回指向地图的指针,还是将地图作为值返回? 这样做的目的当然是避免不必要的数据复制。 问题答案: 在此线程中,您将找到答案: Golang:使用地图参考来访问地图 您不需要在地图上使用指针。 映射类型是引用类型,例如指针或切片[1] 如果需要更改会话,可以使用一个指针:
问题内容: 如何在Python中通过引用传递整数? 我想修改传递给函数的变量的值。我读过Python中的所有内容都是按值传递的,但是必须有一个简单的技巧。例如,在Java中,你可以通过引用类型的,等等。 如何通过引用将整数传递给函数? 最佳做法是什么? 问题答案: 在Python中,这种方式不太有效。Python将引用传递给对象。在函数内部,你有一个对象-你可以随意更改该对象(如果可能)。但是,整
问题内容: 如何在JavaScript中通过引用传递变量?我要对3个变量执行一些操作,因此我想将它们放在for循环中并对每个变量执行操作。 伪代码: 做这个的最好方式是什么? 问题答案: JavaScript中没有可用的“通过引用传递”。您可以传递一个对象(也就是说,您可以按值传递对一个对象的引用),然后让一个函数修改该对象的内容: 您可以使用数字索引遍历数组的属性,并根据需要修改数组的每个单元格
问题内容: 我想知道在您仅读取变量时是否将其作为按引用传递的优良作法,还是应始终将其作为值传递。 引用传递示例: 传递值的示例: 哪个更好 ?例如,如果我要循环运行1000次? 循环示例: 问题答案: 如果您打算传递一个 值 (因此该函数不会对其进行修改) ,则没有理由通过引用传递它:这只会使您的代码更难以理解,因为人们会认为“ 此函数可以修改我将要修改的内容。传递给它-哦,它没有修改? ” 在您