很抱歉写作但使用翻译,我希望你能帮我一个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;
}
}
答案 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.