回撥在客戶端上呼叫方法

概述

在此示例中,2 個客戶端通過伺服器相互傳送資訊。一個客戶端向伺服器傳送一箇中繼到第二個客戶端的號碼。第二個客戶端將數字減半並通過伺服器將其傳送回第一個客戶端。第一個客戶端也這樣做。當任何客戶端返回的數字小於 10 時,伺服器停止通訊。從伺服器到客戶端的返回值(它轉換為字串表示的數字)然後回溯該程序。

  1. 登入伺服器將自身繫結到登錄檔。
  2. 客戶端查詢登入伺服器並使用其資訊呼叫 login 方法。然後:
    • 登入伺服器儲存客戶端資訊。它包含客戶端的存根和回撥方法。
    • 登入伺服器建立並向客戶端返回伺服器存根(連線會話)以進行儲存。它包括伺服器的存根,其方法包括 logout 方法(在本例中未使用)。
  3. 客戶端使用收件人客戶端的名稱和 int 呼叫伺服器的 passInt
  4. 伺服器使用 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 + "\"");
    }
}

執行示例:

  1. 執行登入伺服器。
  2. 使用引數 Client2 Client1 1097 執行客戶端。
  3. 使用引數 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