Java FTPClient (apache commons) storefile() 成功上传文件,然后超时..?

Cul*_*enJ 5 java ftp apache-commons-net

这是我必须将文件上传到 FTP 服务器的一些代码:

private boolean ftpSend(byte[] fileBytes, String filename, HashMap<String, String> endpointAddressData) throws Exception {
    boolean success = false;

    String login = endpointAddressData.get("user");
    String hostname = endpointAddressData.get("host");
    String password = endpointAddressData.get("password");

    String portString = endpointAddressData.get("port");
    int port = (portString == null) ? 21 : Integer.parseInt(portString);

    FTPClient ftpClient = new FTPClient();
    ByteArrayInputStream inputStream = null;
    try {
        ftpClient.setConnectTimeout(10000);
        ftpClient.connect(hostname, port);

        int reply = ftpClient.getReplyCode();

        if(!FTPReply.isPositiveCompletion(reply)) {
            ftpClient.disconnect();

            throw new Exception("FTP server " + hostname + " refused connection.");
        }

        if (password != null) {
            ftpClient.login(login, password);
        } else {
            ftpClient.user(login);
        }

        logger_.debug("FTP - Writing: " + ftpClient.printWorkingDirectory() + "/" + filename + " on host " + endpointAddressData.get("host"));

        inputStream = new ByteArrayInputStream(fileBytes);
        success = ftpClient.storeFile(filename, inputStream);
        inputStream.close();
        success = success && ftpClient.completePendingCommand();

        logger_.debug("FTP - Completed: " + ftpClient.printWorkingDirectory() + "/" + filename + " on host " + endpointAddressData.get("host"));

        ftpClient.disconnect();

    } catch (Exception ex) {
        success = false;

        logger_.error("An error occurred during FTP upload to " + endpointAddressData.get("host") + ".", ex);
    } finally {
        if (ftpClient.isConnected()) {
            ftpClient.abort();
            ftpClient.disconnect();
        }

        if (inputStream != null) {
            inputStream.close();
        }

        return success;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我使用一些测试数据运行它时,上传显然成功完成(这是 FTP 服务器日志):

(000009)01/05/2014 12:13:09 PM - (not logged in) (127.0.0.1)> USER ######
(000009)01/05/2014 12:13:09 PM - (not logged in) (127.0.0.1)> 331 Password required for ######
(000009)01/05/2014 12:13:09 PM - (not logged in) (127.0.0.1)> PASS ########
(000009)01/05/2014 12:13:09 PM - anonymous (127.0.0.1)> 230 Logged on
(000009)01/05/2014 12:13:09 PM - anonymous (127.0.0.1)> PWD ########
(000009)01/05/2014 12:13:09 PM - anonymous (127.0.0.1)> 257 "/" is current directory.
(000009)01/05/2014 12:13:09 PM - anonymous (127.0.0.1)> PORT 127,0,0,1,250,242
(000009)01/05/2014 12:13:09 PM - anonymous (127.0.0.1)> 200 Port command successful
(000009)01/05/2014 12:13:09 PM - anonymous (127.0.0.1)> STOR testFTP1.txt
(000009)01/05/2014 12:13:09 PM - anonymous (127.0.0.1)> 150 Opening data channel for file upload to server of "/testFTP1.txt"
(000009)01/05/2014 12:13:09 PM - anonymous (127.0.0.1)> 226 Successfully transferred "/testFTP1.txt"
(000009)01/05/2014 12:15:10 PM - anonymous (127.0.0.1)> 421 Connection timed out.
(000009)01/05/2014 12:15:10 PM - anonymous (127.0.0.1)> disconnected.
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Cul*_*enJ 4

在调试器中单步执行后,我发现调用ftpClient.completePendingCommand()导致了超时。我猜该命令已经完成,它正在无限期地等待下一个命令。我注释掉了该行,代码很容易完成。

来自 FTPClient 上的 JavaDoc: http://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient.html#completePendingCommand()

有一些 FTPClient 方法无法完成用于完成事务的整个 FTP 命令序列。这些命令需要程序员在收到肯定的中间命令后采取一些操作。程序员的代码完成其操作后,必须调用此方法来接收服务器的完成回复并验证整个事务是否成功。

我想storeFile()(FTP STOR 命令)不是这些方法之一。