执行客户端RMI时出错

时间:2015-05-28 20:00:17

标签: java rmi

很抱歉写作但使用翻译,我希望你能帮我一个RMI测试的例子。

运行客户端时出现以下错误:

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
    java.lang.ClassNotFoundException: client.Pi

项目结构如下。

|-Cliente\
|   |-client\  ComputePi (main class) and Pi(Task)
|      |-->ComputePi.java
|      |-->ComputePi.class
|      |-->Pi.java
|      |-->Pi.class
|   |-compute\
|      |-->Compute.java
|      |-->Compute.class
|      |-->Task.java
|      |-->Task.class
|   |-public\
|      |-classes\
|         |-->compute.jar 
|         |-client\
|            |--> Pi.class
|-->client.policy

|-Servidor\
|   |-compute\
|      |-->Compute.java
|      |-->Compute.class
|      |-->Task.java
|      |-->Task.class
|   |-engine\
|      |-->ComputeEngine.java
|      |-->ComputeEngine.class
|   |-public\
|      |-classes\
|         |-->compute.jar 
|-->server.policy

服务器启动正常,但是当我启动客户端时,它会向我发送上面显示的错误。当我运行客户端时,我按如下方式执行:

java -cp c:\Users\Mauricio\Documents\RMI\Cliente;c:\Users\Mauricio\Documents\RMI\Cliente\public\classes\compute.jar
   -Djava.rmi.server.codebase=file:/c:/Users/Mauricio/Documents/RMI/Cliente/public/classes/
   -Djava.security.policy=c:/Users/Mauricio/Documents/RMI/Cliente/client.policy 
   client.ComputePi 127.0.0.1 45

你能帮我理解导致这个错误的原因吗?

很抱歉没有提前代码。

课堂计算

package compute;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Compute extends Remote {
    <T> T executeTask(Task<T> t) throws RemoteException;
}

课程任务

package compute;

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

Class ComputePi

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();
        }
    }    
}

Class Pi

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;
    }
}

Class ComputeEngine

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;
    }
}

2 个答案:

答案 0 :(得分:1)

我相信你得到的错误是因为你在启动服务器时错过了以下标志:

-Djava.rmi.server.useCodebaseOnly=false

问题在于服务器,而不是客户端。客户端报告服务器的错误。

在我写这篇文章的时候,Oracle RMI教程缺少这个标志;所以,这不是你的错。

https://docs.oracle.com/javase/tutorial/rmi/running.html

如果您错过了该标志,服务器将不会加载它自己的代码库中没有的任何代码。换句话说,如果客户端与服务器位于不同的计算机上,并且Pi类仅存在于客户端上,则服务器将无法加载它。您看到的错误是我在添加标志之前遇到的确切错误。

我的理解是,从JVM v1.7开始,useCodebaseOnly的默认值为true。 (真正的值允许更高的安全性,但是会导致教程损坏。)

简而言之,将设置为false的标志添加到服务器的启动命令中。祝你好运!

答案 1 :(得分:0)

  

java.lang.ClassNotFoundException:client.Pi

服务器的CLASSPATH或客户端的代码库中没有client.Pi可用。除非服务器和客户端都在同一台计算机上,否则file:代码库不起作用,在这种情况下,使用代码库功能几乎没有任何意义。

另请参阅@ Mario的回答java.rmi.server.useCodebaseOnly.