在RMI中通过引用问题?

时间:2010-08-28 14:50:09

标签: java debugging distributed rmi pass-by-reference

有人可以告诉我,为什么这个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());
            }
        }

    }

3 个答案:

答案 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