Spec-Zone .ru
спецификации, руководства, описания, API
След: RMI
Создание Клиентской Программы
Домашняя страница > RMI

Создание Клиентской Программы

Вычислить механизм является относительно простой программой: это выполняет задачи, которые вручаются этому. Клиенты для вычислить механизма более сложны. Клиент должен вызвать вычислить механизм, но он также должен определить задачу, которая будет выполняться вычислить механизмом.

Два отдельных класса составляют клиент в нашем примере. Первый class, ComputePi, ищет и вызывает a Compute объект. Второй class, Pi, реализации Task взаимодействуйте через интерфейс и определяет работу, которая будет сделана вычислить механизмом. Задание Pi class должен вычислить значение символ пик некоторому числу десятичных разрядов.

Неудаленное Task интерфейс определяется следующим образом:

package compute;

public interface Task<T> {
    T execute();
}

Код, который вызывает a Compute методы объекта должны получить ссылку на тот объект, создать a Task объект, и затем запрашивает, чтобы задача была выполнена. Определение задачи class Pi показывается позже. A Pi объект создается с единственным параметром, требуемой точностью результата. Результатом выполнения задачи является a java.math.BigDecimal представление символ пивычисленного к указанной точности.

Вот исходный код для client.ComputePi, основной клиент class:

package client;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.math.BigDecimal;
import compute.Compute;

public class ComputePi {
    public static void main(String args[]) {
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }
        try {
            String name = "Compute";
            Registry registry = LocateRegistry.getRegistry(args[0]);
            Compute comp = (Compute) registry.lookup(name);
            Pi task = new Pi(Integer.parseInt(args[1]));
            BigDecimal pi = comp.executeTask(task);
            System.out.println(pi);
        } catch (Exception e) {
            System.err.println("ComputePi exception:");
            e.printStackTrace();
        }
    }    
}

Как ComputeEngine сервер, клиент начинает, устанавливая менеджера безопасности. Этот шаг необходим, потому что процесс получения тупика удаленного объекта сервера мог потребовать загрузки определения class от сервера. Для RMI, чтобы загрузить классы, менеджер безопасности должен быть в силе.

После установки менеджера безопасности клиент создает имя, чтобы использовать, чтобы искать a Compute удаленный объект, используя то же самое имя, используемое ComputeEngine связывать его удаленный объект. Кроме того, клиент использует LocateRegistry.getRegistry API, чтобы синтезировать удаленную ссылку на реестр на узле сервера. Значение первого параметра командной строки, args[0], имя удаленного узла на который Compute объектные выполнения. Клиент тогда вызывает lookup метод на реестре, чтобы искать удаленный объект по имени в реестре узла сервера. Определенная перегрузка LocateRegistry.getRegistry используемый, у которого есть сингл String параметр, возвращает ссылку на реестр в именованном узле и порту реестра значения по умолчанию, 1099. Следует использовать перегрузку, которая имеет int параметр, если реестр создается на порту кроме 1099.

Затем, клиент создает новое Pi объект, передавая к Pi конструктор значение второго параметра командной строки, args[1], проанализированный как целое число. Этот параметр указывает на число десятичных разрядов, чтобы использовать в вычислении. Наконец, клиент вызывает executeTask метод Compute удаленный объект. Объект, который передают в executeTask вызов возвращает объект типа BigDecimal, который программа хранит в переменной result. Наконец, программа печатает результат. Следующее число изображает поток сообщений среди ComputePi клиент, rmiregistry, и ComputeEngine.

поток сообщений между вычислить механизмом, реестром, и клиентом.

Pi class реализует Task взаимодействуйте через интерфейс и вычисляет значение символ пик конкретному количеству десятичных разрядов. Для этого примера фактический алгоритм незначителен. То, что важно, - то, что алгоритм в вычислительном отношении дорог, означая, что Вы хотели бы выполнить его на способном сервере.

Вот исходный код для client.Pi, class, который реализует Task интерфейс:

package client;

import compute.Task;
import java.io.Serializable;
import java.math.BigDecimal;

public class Pi implements Task<BigDecimal>, Serializable {

    private static final long serialVersionUID = 227L;

    /** constants used in pi computation */
    private static final BigDecimal FOUR =
        BigDecimal.valueOf(4);

    /** rounding mode to use during pi computation */
    private static final int roundingMode = 
        BigDecimal.ROUND_HALF_EVEN;

    /** digits of precision after the decimal point */
    private final int digits;
    
    /**
     * Construct a task to calculate pi to the specified
     * precision.
     */
    public Pi(int digits) {
        this.digits = digits;
    }

    /**
     * Calculate pi.
     */
    public BigDecimal execute() {
        return computePi(digits);
    }

    /**
     * Compute the value of pi to the specified number of 
     * digits after the decimal point.  The value is 
     * computed using Machin's formula:
     *
     *          pi/4 = 4*arctan(1/5) - arctan(1/239)
     *
     * and a power series expansion of arctan(x) to 
     * sufficient precision.
     */
    public static BigDecimal computePi(int digits) {
        int scale = digits + 5;
        BigDecimal arctan1_5 = arctan(5, scale);
        BigDecimal arctan1_239 = arctan(239, scale);
        BigDecimal pi = arctan1_5.multiply(FOUR).subtract(
                                  arctan1_239).multiply(FOUR);
        return pi.setScale(digits, 
                           BigDecimal.ROUND_HALF_UP);
    }
    /**
     * Compute the value, in radians, of the arctangent of 
     * the inverse of the supplied integer to the specified
     * number of digits after the decimal point.  The value
     * is computed using the power series expansion for the
     * arc tangent:
     *
     * arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + 
     *     (x^9)/9 ...
     */   
    public static BigDecimal arctan(int inverseX, 
                                    int scale) 
    {
        BigDecimal result, numer, term;
        BigDecimal invX = BigDecimal.valueOf(inverseX);
        BigDecimal invX2 = 
            BigDecimal.valueOf(inverseX * inverseX);

        numer = BigDecimal.ONE.divide(invX,
                                      scale, roundingMode);

        result = numer;
        int i = 1;
        do {
            numer = 
                numer.divide(invX2, scale, roundingMode);
            int denom = 2 * i + 1;
            term = 
                numer.divide(BigDecimal.valueOf(denom),
                             scale, roundingMode);
            if ((i % 2) != 0) {
                result = result.subtract(term);
            } else {
                result = result.add(term);
            }
            i++;
        } while (term.compareTo(BigDecimal.ZERO) != 0);
        return result;
    }
}

Отметьте, что все сериализуемые классы, реализуют ли они Serializable взаимодействуйте через интерфейс прямо или косвенно, должен объявить a private static final поле называют serialVersionUID гарантировать совместимость сериализации между версиями. Если никакая предыдущая версия class не была выпущена, то значение этого поля может быть любым long значение, подобное 227L используемый Pi, пока значение последовательно используется в будущих версиях. Если предыдущая версия class была выпущена без явного serialVersionUID объявление, но совместимость сериализации с той версией важно, тогда значение по умолчанию, неявно вычисленное значение для предыдущей версии должно использоваться для значения явного объявления новой версии. serialver инструмент может быть выполнен против предыдущей версии, чтобы определить значение по умолчанию вычисленное значение для этого.

Самая интересная функция этого примера то, что Compute объект реализации никогда не нуждается Pi Определение class до a Pi в объекте передают как параметр executeTask метод. В той точке код для class загружается RMI в Compute виртуальная машина Java объекта, execute метод вызывается, и код задачи выполняется. Результат, который в случае Pi задачей является a BigDecimal возразите, возвращается клиенту вызова, где это используется, чтобы напечатать результат вычисления.

Факт, что предоставленный Task объект вычисляет значение Pi не важно ComputeEngine объект. Вы могли также реализовать задачу, которая, например, генерирует случайное простое число при использовании вероятностного алгоритма. Та задача также была бы в вычислительном отношении интенсивна и поэтому хороший кандидат на передачу к ComputeEngine, но это потребовало бы совсем другого кода. Этот код мог также быть загружен когда Task объект передают к a Compute объект. Только способом, которым алгоритм для того, чтобы вычислить символ пивводится при необходимости, код, который генерирует случайное простое число, был бы введен при необходимости. Compute объект знает только, что каждый объект получает реализации execute метод. Compute объект не знает, и не должен знать, что делает реализация.


Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Реализация Удаленного Интерфейса
Следующая страница: Компиляция и Выполнение Примера