【发布时间】:2013-08-13 20:07:19
【问题描述】:
我正在编写一个可以进行 rmi 调用的 servlet。我已经编写了 RMI 服务器并使用 java swing 客户端对其进行了测试,一切正常。但是我在使用 servlet 时遇到了问题。 当用户打开主网页时,servlet 会自动调用一个 rmi 方法来检索数据库上的一些信息,然后构建网页来显示。 当用户单击某个链接触发另一个调用另一个 rmi 方法的 servlet 时,我得到一个错误:
java.rmi.ConnectException: Connection refused to host: 192.168.1.101; nested exception is:
java.net.ConnectException: Connection refused
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:340)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at project.RemoteClass.getEngine(RemoteClass.java:33)
at project.MainServlet.processRequest(MainServlet.java:57)
at project.MainServlet.doGet(MainServlet.java:176)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
Caused by: java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:579)
at java.net.Socket.connect(Socket.java:528)
at java.net.Socket.<init>(Socket.java:425)
at java.net.Socket.<init>(Socket.java:208)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:40)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:146)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:613)
我认为这可能是由于我如何查找注册表并将其传递给 servets。 为了避免在每个 servlet 中编写每次查找 RMI 代码,我想做一个类(如 JDBC 客户端上使用的 ConnectionManager)一个查找注册表并将其返回给调用 servlet 的类:
public class RemoteClass {
private RemoteClass(){}
private static Registry registry = null;
private static RemoteInterface interface_engine = null;
private static final String rmiAddress = "192.168.1.101";
private static final int rmiPort = 22222;
private static final String skeleton = "ProjRMISkeleton";
public static RemoteInterface getEngine() throws RemoteException {
registry = LocateRegistry.getRegistry(rmiAddress, rmiPort);
try {
interface_engine = (RemoteInterface) registry.lookup(skeleton);
} catch (RemoteException ex) {
Logger.getLogger(MainServlet.class.getName()).log(Level.SEVERE, null, ex);
} catch (NotBoundException ex) {
Logger.getLogger(MainServlet.class.getName()).log(Level.SEVERE, null, ex);
}
return interface_engine;
}
}
当此代码执行 registry.lookup 方法时会发生该错误。 我该如何解决?
【问题讨论】:
-
真的有192.168.1.101的服务器监听22222端口吗?在正确的界面上?可以telnet过来看看能不能用吗?
-
当然,它运作良好。也因为如果它不起作用,第一个 rmi 调用也应该失败。
-
您真的需要不断地重新分配
interface_engine静态字段吗? -
嗯,不,它不应该是静态的,但我不想每次 servlet 需要调用远程方法时都创建一个 RemoteClass 对象!
-
但你仍在这样做。请注意,每次方法执行
RemoteClass#getEngine时,您总是执行interface_engine = (RemoteInterface) registry.lookup(skeleton);,这很奇怪(甚至很奇怪,因为该方法不是线程安全的)。