2012-05-02 109 views
3

长话短说,我有一个RMI服务器和客户端。服务器和客户端能够相互进行RMI呼叫。客户端连接到服务器后,服务器可能会在客户端上快速连续进行数百次方法调用。什么可能导致RMI方法调用间歇性失败?

问题是这样的 - 对于大量的服务器到客户端方法调用的结束,有些会失败,因为RMI声称它无法建立从服务器到客户端的连接,即使数百个呼叫在它之前将会成功。我不能发表任何真正的代码,因为这个项目是相当大(约50K线),但这里是被抛出的异常的完整堆栈跟踪:

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is: 
java.net.SocketException: Connection reset 
at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source) 
at sun.rmi.transport.Transport$1.run(Unknown Source) 
at java.security.AccessController.doPrivileged(Native Method) 
at sun.rmi.transport.Transport.serviceCall(Unknown Source) 
at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source) 
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source) 
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source) 
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) 
at java.lang.Thread.run(Unknown Source) 
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source) 
at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source) 
at sun.rmi.server.UnicastRef.invoke(Unknown Source) 
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source) 
at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source) 
at $Proxy0.findClassDefinition(Unknown Source) 
at com.fabric.network.NetworkClassLoader.findClass(NetworkClassLoader.java:111) 
at java.lang.ClassLoader.loadClass(Unknown Source) 
at com.fabric.network.NetworkClassLoader.loadClass(NetworkClassLoader.java:131) 
at java.lang.ClassLoader.loadClass(Unknown Source) 
at com.fabric.network.MessageSocket$CustomObjectInputStream.resolveClass(MessageSocket.java:171) 
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source) 
at java.io.ObjectInputStream.readClassDesc(Unknown Source) 
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
at java.io.ObjectInputStream.readObject0(Unknown Source) 
at java.io.ObjectInputStream.defaultReadFields(Unknown Source) 
at java.io.ObjectInputStream.readSerialData(Unknown Source) 
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
at java.io.ObjectInputStream.readObject0(Unknown Source) 
at java.io.ObjectInputStream.defaultReadFields(Unknown Source) 
at java.io.ObjectInputStream.readSerialData(Unknown Source) 
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
at java.io.ObjectInputStream.readObject0(Unknown Source) 
at java.io.ObjectInputStream.readObject(Unknown Source) 
at com.fabric.network.MessageSocket.receive(MessageSocket.java:118) 
at com.fabric.application.driver.NodeRemoteDriver$IncomingMessageThread.run(NodeRemoteDriver.java:205) 
Caused by: java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is: 
java.net.SocketException: Connection reset 
at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source) 
at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source) 
at sun.rmi.server.UnicastRef.invoke(Unknown Source) 
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source) 
at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source) 
at $Proxy2.findClassDefinition(Unknown Source) 
at com.fabric.network.ClassDefinitionCache.findClassDefinition(ClassDefinitionCache.java:78) 
at com.fabric.management.host.NodeManagementServices.findClassDefinition(NodeManagementServices.java:231) 
at sun.reflect.GeneratedMethodAccessor16.invoke(Unknown Source) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
at java.lang.reflect.Method.invoke(Unknown Source) 
at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source) 
at sun.rmi.transport.Transport$1.run(Unknown Source) 
at java.security.AccessController.doPrivileged(Native Method) 
at sun.rmi.transport.Transport.serviceCall(Unknown Source) 
at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source) 
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source) 
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source) 
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) 
at java.lang.Thread.run(Unknown Source) 
Caused by: java.net.SocketException: Connection reset 
at java.net.SocketInputStream.read(Unknown Source) 
at java.io.BufferedInputStream.fill(Unknown Source) 
at java.io.BufferedInputStream.read(Unknown Source) 
at java.io.DataInputStream.readByte(Unknown Source) 
... 21 more 

再次,抱歉,我不能提供太多的代码的方式,但我不一定要求修复代码 - 我只是想围绕为什么会发生这种情况。

编辑

添加完整的堆栈跟踪。

+0

可能是你的:http://docs.oracle.com/javase/jndi/tutorial/objects/storing/remote.html –

+0

我的问题可能有点愚蠢,但你是否检查客户端是否有任何异常侧? –

+0

@MartinPrakash是的。这*是客户端的一个例外。 – EJP

回答

6

好吧,在将我所有的头发都拉出来后,事实证明RMI试图打开太多的端口。我正在使用自定义的RMISocketFactory实现。这个自定义实现是一个单身人士,所以我不认为有必要实施hashCode()equals()。确实是一个非常痛苦的错误...

原来,RMI不会重用套接字,如果RMI确定它需要创建的套接字是由RMISocketFactory创建的,它不等同于创建套接字的工厂它想要重用。 RMI依靠equals()hashCode()执行此检查。一旦我在自定义套接字工厂中正确实现了这两个方法,这些间歇性问题就消失了。

这个问题的描述可以在这里找到:

http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/faq.html

无论如何,感谢所有在这个考虑看看,我当然感谢您的时间!

其他信息

事实证明,我是用快用完了的传入的连接请求,这也促成了连接队列中的空间ServerSocket被丢弃。使用构造函数new ServerSocket(port, newConnectionQueueSize, bindAddress)和更大的newConnectionQueueSize也有助于解决此问题。