Apache Commons FTPClient挂起如何解决?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (401)

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

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)时,此代码加载完美,并开始顺利工作。但是,每次在某个点或另一个点,它似乎只是挂起。我的意思是:

  • 没有堆转储存在
  • Tomcat仍在运行(我可以看到它的pid,并可以登录到Web管理器应用程序)
  • 在经理应用程序内部,我可以看到我的WAR仍在运行/启动
  • catalina.out 和我的应用程序特定的日志显示没有任何异常被抛出的迹象

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

这告诉我在文件的实际轮询/获取过程中发生了挂起,我能够发现哪一点与FTPClient死锁有关。这让我想知道这些是否是相同的问题(如果是的话,我会很乐意删除这个问题!)。不过,我不认为认为它们是相同的(我没有看到我日志中的同样的例外)。

一位同事提到它可能是一个“被动”与“主动”FTP的东西。没有真正知道的区别,我由FTPClient场有点困惑ACTIVE_REMOTE_DATA_CONNECTION_MODEPASSIVE_REMOTE_DATA_CONNECTION_MODE等等,不知道为什么情绪这么想过,作为一个潜在的问题。

既然我在Throwable这里采取了最后的手段,如果出现问题,我会希望在日志中看到一些东西。埃尔戈,我觉得这是一个明确的悬挂问题。

有任何想法吗?不幸的是,我对这里的FTP内部知识不够了解,无法做出明确的诊断。这可能是服务器端的东西吗?有关FTP服务器?

提问于
用户回答回答于

这可能是一些事情,但你朋友的建议是值得的。

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

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

用户回答回答于

可以使用FTPClient.setBufferSize()增加缓冲区大小;

   /**
 * Download encrypted and configuration files.
 * 
 * @throws SocketException
 * @throws IOException
 */
public void downloadDataFiles(String destDir) throws SocketException,
        IOException {

    String filename;
    this.ftpClient.connect(ftpServer);
    this.ftpClient.login(ftpUser, ftpPass);

    /* CHECK NEXT 4 Methods (included the commented) 
    *  they were very useful for me!
    *  and icreases the buffer apparently solve the problem!!
    */
    //  ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
    log.debug("Buffer Size:" + ftpClient.getBufferSize());
    this.ftpClient.setBufferSize(1024 * 1024);
    log.debug("Buffer Size:" + ftpClient.getBufferSize());


    /*  
     *  get Files to download
     */
    this.ftpClient.enterLocalPassiveMode();
    this.ftpClient.setAutodetectUTF8(true);
            //this.ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
    this.ftpClient.enterLocalPassiveMode();
    FTPFile[] ftpFiles = ftpClient
            .listFiles(DefaultValuesGenerator.LINPAC_ENC_DIRPATH);

    /*
     * Download files
     */
    for (FTPFile ftpFile : ftpFiles) {

        // Check if FTPFile is a regular file           
        if (ftpFile.getType() == FTPFile.FILE_TYPE) {
            try{

            filename = ftpFile.getName();

            // Download file from FTP server and save
            fos = new FileOutputStream(destDir + filename);

            //I don't know what useful are these methods in this step
            // I just put it for try
            this.ftpClient.enterLocalPassiveMode();
            this.ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            this.ftpClient.setAutodetectUTF8(true);
            this.ftpClient.enterLocalPassiveMode();

            ftpClient.retrieveFile(
                    DefaultValuesGenerator.LINPAC_ENC_DIRPATH + filename,
                    fos
                    );

            }finally{
                fos.flush();
                fos.close();                }
        }
    }
    if (fos != null) {
        fos.close();
    }
}

扫码关注云+社区

领取腾讯云代金券