Commons Net FTP死锁问题?

5

我有一个进程,应该每5分钟将文件通过ftp发送到远程位置。

它似乎已经卡住了几个小时,没有发送文件。

我取了一个线程转储来查看情况,这是我的线程状态:

"SPPersister" prio=6 tid=0x03782400 nid=0x16c4 runnable [0x0468f000..0x0468fd14]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(Unknown Source)
        at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
        at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
        at sun.nio.cs.StreamDecoder.read(Unknown Source)
        - locked <0x239ebea0> (a java.io.InputStreamReader)
        at java.io.InputStreamReader.read(Unknown Source)
        at java.io.BufferedReader.fill(Unknown Source)
        at java.io.BufferedReader.readLine(Unknown Source)
        - locked <0x239ebea0> (a java.io.InputStreamReader)
        at java.io.BufferedReader.readLine(Unknown Source)
        at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:294)
        at org.apache.commons.net.ftp.FTP._connectAction_(FTP.java:364)
        at org.apache.commons.net.ftp.FTPClient._connectAction_(FTPClient.java:540)
        at org.apache.commons.net.SocketClient.connect(SocketClient.java:178)
        at org.apache.commons.net.SocketClient.connect(SocketClient.java:268)
        ...

我正在使用以下代码进行连接:
FTPClient client = new FTPClient();
client.setConnectTimeout(10000);
client.connect(host); // <-- stuck here
client.setDataTimeout(20000);
client.setSoTimeout(20000);
client.login(user, pass);
client.changeWorkingDirectory(dir);

连接尝试不应该在10秒内超时吗?
2个回答

4

是的,也不是。

如果连接没有成功,那么连接将在十秒内超时,但实际上连接可能已经成功了,现在正在尝试从套接字读取数据,很可能是为了先完成初始FTP helo序列[1]。事实上,查看connectAction()的javadoc,这就是你的堆栈跟踪卡住的地方。

在调用连接之前,您可以尝试设置数据超时时间,这样它可能会按照您预期的方式失败。如果这样做不起作用,您很可能需要向apache-commons提出错误报告这个错误几乎肯定是您所看到的问题。

[1] 根据RFC959:

一个重要的信息回复组是连接问候语。在正常情况下,当连接完成时,服务器会发送一个220回复“等待输入”。用户应该在发送任何命令之前等待这个问候消息。如果服务器无法立即接受输入,则应立即发送120个“预期延迟”回复和一个220个回复。然后用户就知道如果有延迟就不要挂断电话。这就是为什么FTPClient类正在等待来自对方的输入的原因。

听起来像是这个 bug:http://www.mail-archive.com/commons-dev@jakarta.apache.org/msg55067.html - pstanton
@pstanton:谢谢,我已经更新了答案并包含了一个指向该错误的链接。 - Paul Wagland
我记得我在connect调用之后放置了setDataTimeout调用,因为我认为它可能像setSoTimeout调用一样,其文档规定只能在connect之后使用。现在已经将setDataTimeout提前,希望这可以解决问题。谢谢。 - pstanton
@pstanton:可能吧...但是你需要测试一下,因为我不能确定回答。 - Paul Wagland

2
我们曾经有一段Java代码尝试从设备中进行FTP传输,但是它使用commons-net/ftp时会出现无法解释的卡顿,就像你现在遇到的情况一样。经过大量搜索,我找到了某个缺陷报告,表明这是commons-net/ftp的一个缺陷。当你等待响应时,网络断开(我们的无线网络不稳定),缺陷就会发生。一旦发生,它就会进入一个永远不会返回的等待状态。
我们找到的解决方案是使用不同的库。虽然有很多库可供选择,但我们使用的是这个:http://www.enterprisedt.com/products/edtftpj/overview.html

你可以通过显式设置数据超时时间来解决这个问题...或者使用不同的库;-) - Paul Wagland

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接