有人可以告诉我,为什么这个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;
}
我想作为业务逻辑(gamelogic)的对象。
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());
}
}
}
答案 0 :(得分:2)
更改
private List<TTTClientRemote> serverList;
要:
private List<TTTClientRemote> serverList = new ArrayList<TTTClientRemote>();
或者在updateClients();中的for()之前的某处初始化它。
答案 1 :(得分:1)
你的问题不够明确,但是:
调试代码,或者在获得NPE的行之前放置一些日志(只是System.out.println)。也许你的名单仍然是空的。
public void updateClients() throws RemoteException {
**if (serverList != null) {**
for (TTTClientRemote aClient : serverList) {
aClient.updateClients("slam");
}
}
}
答案 2 :(得分:1)
Ernest Friedman-Hill 在link text http://www.coderanch.com/t/508960/java/java/pass-reference 的回答:
问题的根源在于RMI不支持按引用传递,因此使消息类可序列化并在该可序列化类中创建ServerServices的远程实例可以使此应用程序正常工作
OR
在客户端类中创建Message类的远程实例,并从RMI注册表中发布它也可以工作。
在此代码中,使用本地引用而不是远程,因此它从Serverservices类获取列表中的0个元素。
再次感谢: Ernest Friedman-Hill 。