回调在客户端上调用方法
概述
在此示例中,2 个客户端通过服务器相互发送信息。一个客户端向服务器发送一个中继到第二个客户端的号码。第二个客户端将数字减半并通过服务器将其发送回第一个客户端。第一个客户端也这样做。当任何客户端返回的数字小于 10 时,服务器停止通信。从服务器到客户端的返回值(它转换为字符串表示的数字)然后回溯该进程。
- 登录服务器将自身绑定到注册表。
- 客户端查找登录服务器并使用其信息调用 login方法。然后:- 登录服务器存储客户端信息。它包含客户端的存根和回调方法。
- 登录服务器创建并向客户端返回服务器存根(连接或会话)以进行存储。它包括服务器的存根,其方法包括 logout方法(在本例中未使用)。
 
- 客户端使用收件人客户端的名称和 int调用服务器的passInt。
- 服务器使用 int调用收件人客户端上的half。这将启动来回(调用和回调)通信,直到服务器停止。
共享远程接口
登录服务器:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteLogin extends Remote {
    RemoteConnection login(String name, RemoteClient client) throws RemoteException;
}
服务器:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteConnection extends Remote {
    void logout() throws RemoteException;
    String passInt(String name, int i) throws RemoteException;
}
客户端:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteClient extends Remote {
    void half(int i) throws RemoteException;
}
实施
登录服务器:
package callbackServer;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
import callbackRemote.RemoteLogin;
public class LoginServer implements RemoteLogin {
    static Map<String, RemoteClient> clients = new HashMap<>();
    @Override
    public RemoteConnection login(String name, RemoteClient client) {
        Connection connection = new Connection(name, client);
        clients.put(name, client);
        System.out.println(name + " logged in");
        return connection;
    }
    public static void main(String[] args) {
        try {
            Registry reg = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
            LoginServer server = new LoginServer();
            UnicastRemoteObject.exportObject(server, Registry.REGISTRY_PORT);
            reg.rebind("LoginServerName", server);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}
服务器:
package callbackServer;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.Unreferenced;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
public class Connection implements RemoteConnection, Unreferenced {
    RemoteClient client;
    String name;
    public Connection(String name, RemoteClient client) {
        this.client = client;
        this.name = name;
        try {
            UnicastRemoteObject.exportObject(this, Registry.REGISTRY_PORT);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void unreferenced() {
        try {
            UnicastRemoteObject.unexportObject(this, true);
        } catch (NoSuchObjectException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void logout() {
        try {
            UnicastRemoteObject.unexportObject(this, true);
        } catch (NoSuchObjectException e) {
            e.printStackTrace();
        }
    }
    @Override
    public String passInt(String recipient, int i) {
        System.out.println("Server received from " + name + ":" + i);
        if (i < 10)
            return String.valueOf(i);
        RemoteClient client = LoginServer.clients.get(recipient);
        try {
            client.half(i);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return String.valueOf(i);
    }
}
客户端:
package callbackClient;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
import callbackRemote.RemoteLogin;
public class Client implements RemoteClient {
    RemoteConnection connection;
    String name, target;
    Client(String name, String target) {
        this.name = name;
        this.target = target;
    }
    public static void main(String[] args) {
        Client client = new Client(args[0], args[1]);
        try {
            Registry reg = LocateRegistry.getRegistry();
            RemoteLogin login = (RemoteLogin) reg.lookup("LoginServerName");
            UnicastRemoteObject.exportObject(client, Integer.parseInt(args[2]));
            client.connection = login.login(client.name, client);
        } catch (RemoteException | NotBoundException e) {
            e.printStackTrace();
        }
        if ("Client1".equals(client.name)) {
            try {
                client.connection.passInt(client.target, 120);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void half(int i) throws RemoteException {
        String result = connection.passInt(target, i / 2);
        System.out.println(name + " received: \"" + result + "\"");
    }
}
运行示例:
- 运行登录服务器。
- 使用参数 Client2 Client1 1097运行客户端。
- 使用参数 Client1 Client2 1098运行客户端。
由于有 3 个 JVM,输出将出现在 3 个控制台中。在这里他们被混为一谈:
Client2 登录
Client1 登录
从 Client1 收到的
服务器 :120 从 Client2 收到的服务器:60
从 Client1 收到的
服务器 :30 从 Client2 收到的服务器:15
从 Client1 收到的服务器:7
收到 Client1: 收到7
Client2:收到15
Client1 :30
Client2 收到:60