Apache Commons FTPClient 挂起

2022-01-09 00:00:00 ftp ftp-client java apache-commons-net

我们正在使用以下 Apache Commons Net FTP 代码连接到 FTP 服务器,轮询一些目录中的文件,如果找到文件,则将它们检索到本地计算机:

We are using the following Apache Commons Net FTP code to connect to an FTP server, poll some directories for files, and if files are found, to retrieve them to the local machine:

try {
logger.trace("Attempting to connect to server...");

// Connect to server
FTPClient ftpClient = new FTPClient();
ftpClient.setConnectTimeout(20000);
ftpClient.connect("my-server-host-name");
ftpClient.login("myUser", "myPswd");
ftpClient.changeWorkingDirectory("/loadables/");

// Check for failed connection
if(!FTPReply.isPositiveCompletion(ftpClient.getReplyCode()))
{
    ftpClient.disconnect();
    throw new FTPConnectionClosedException("Unable to connect to FTP server.");
}

// Log success msg
logger.trace("...connection was successful.");

// Change to the loadables/ directory where we poll for files
ftpClient.changeWorkingDirectory("/loadables/");    

// Indicate we're about to poll
logger.trace("About to check loadables/ for files...");

// Poll for files.
FTPFile[] filesList = oFTP.listFiles();
for(FTPFile tmpFile : filesList)
{
    if(tmpFile.isDirectory())
        continue;

    FileOutputStream fileOut = new FileOutputStream(new File("tmp"));
    ftpClient.retrieveFile(tmpFile.getName(), fileOut);
    // ... Doing a bunch of things with output stream
    // to copy the contents of the file down to the local
    // machine. Ommitted for brevity but I assure you this
    // works (except when the WAR decides to hang).
    //
    // This was used because FTPClient doesn't appear to GET
    // whole copies of the files, only FTPFiles which seem like
    // file metadata...
}

// Indicate file fetch completed.
logger.trace("File fetch completed.");

// Disconnect and finish.
if(ftpClient.isConnected())
    ftpClient.disconnect();

logger.trace("Poll completed.");
} catch(Throwable t) {
    logger.trace("Error: " + t.getMessage());
}

我们计划每分钟每分钟运行一次.当部署到 Tomcat (7.0.19) 时,此代码加载得非常好,并且可以顺利开始工作.但每次,在某个时候,它似乎只是挂起.我的意思是:

We have this scheduled to run every minute, on the minute. When deployed to Tomcat (7.0.19) this code loads up perfectly fine and begins working without a hitch. Every time though, at some point or another, it seems to just hang. By that I mean:

  • 不存在堆转储
  • Tomcat 仍在运行(我可以看到它的 pid 并且可以登录到 Web 管理器应用程序)
  • 在管理器应用中,我可以看到我的 WAR 仍在运行/启动
  • catalina.out 和我的特定于应用程序的日志显示没有任何异常被抛出的迹象
  • No heap dumps exist
  • Tomcat is still running (I can see its pid and can log into the web manager app)
  • Inside the manager app, I can see my WAR is still running/started
  • catalina.out and my application-specific log show no signs of any exceptions being thrown

所以 JVM 仍在运行.Tomcat 仍在运行,我部署的 WAR 仍在运行,但它只是挂起.有时运行 2 小时然后挂起;其他时候它会运行几天然后挂起.但是当它挂起时,它会在读取 About to check loadables/for files... 的行(我确实在日志中看到)和读取 File fetch 的行之间这样做完成.(我没看到).

So the JVM is still running. Tomcat is still running, and my deployed WAR is still running, but its just hanging. Sometimes it runs for 2 hours and then hangs; other times it runs for days and then hangs. But when it does hang, it does so between the line that reads About to check loadables/ for files... (which I do see in the logs) and the line that reads File fetch completed. (which I don't see).

这告诉我在文件的实际轮询/获取过程中发生了挂起,这使我指向了与 this question 我能够找到与 FTPClient 死锁有关的问题.这让我想知道这些问题是否相同(如果是,我会很乐意删除这个问题!).但是我不认为相信它们是相同的(我在我的日志中没有看到相同的异常).

This tells me the hang occurs during the actual polling/fetching of the files, which kind of points me in the same direction as this question that I was able to find which concerns itself with FTPClient deadlocking. This has me wondering if these are the same issues (if they are, I'll happily delete this question!). However I don't think believe they're the same (I don't see the same exceptions in my logs).

一位同事提到它可能是被动"与主动"的 FTP 事情.不知道有什么区别,我对 FTPClient 字段 ACTIVE_REMOTE_DATA_CONNECTION_MODEPASSIVE_REMOTE_DATA_CONNECTION_MODE 等感到有些困惑,并且不知道 SO 认为这是一个潜在问题.

A co-worker mentioned it might be a "Passive" vs. "Active" FTP thing. Not really knowing the difference, I am a little confused by the FTPClient fields ACTIVE_REMOTE_DATA_CONNECTION_MODE, PASSIVE_REMOTE_DATA_CONNECTION_MODE, etc. and didn't know what SO thought about that as being a potential issue.

由于我在这里将 Throwable 作为最后的手段,因此如果出现问题,我本来希望在日志中看到 something.因此,我觉得这是一个明确的挂起问题.

Since I'm catching Throwables as a last resort here, I would have expected to see something in the logs if something is going wrong. Ergo, I feel like this is a definite hang issue.

有什么想法吗?不幸的是,我对这里的 FTP 内部知识知之甚少,无法做出明确的诊断.这可能是服务器端的东西吗?跟FTP服务器有关吗?

Any ideas? Unfortunately I don't know enough about FTP internals here to make a firm diagnosis. Could this be something server-side? Related to the FTP server?

推荐答案

这可能是很多事情,但你朋友的建议是值得的.

This could be a number of things, but your friend's suggestion would be worthwhile.

试试 ftpClient.enterLocalPassiveMode(); 看看是否有帮助.

Try ftpClient.enterLocalPassiveMode(); to see if it helps.

我还建议将断开连接放在 finally 块中,这样它就不会留下连接.

I would also suggest to put the disconnect in the finally block so that it never leaves a connection out there.

相关文章