当前位置: 首页 > 知识库问答 >
问题:

FTPSClient检索文件()挂

陆俊迈
2023-03-14

我正在创建一个ApacheFTPS客户端(因为远程服务器不允许普通FTP)。我可以毫无问题地连接和删除文件,但在使用retrieveFile()或retrieveFileStream()时,它会挂起。

出于某种原因,非常小的文件确实会传输(高达5792字节),但其他任何东西都会给出以下PrintExpldListener输出:

运行:
220------欢迎使用纯FTPd[privsep][TLS]------
220您是允许的50个用户中的2个<当地时间现在是19:42。服务器端口:21
220这是一个专用系统-此服务器上也不欢迎匿名登录
220-IPv6连接
220您将在15分钟不活动后断开连接
验证TLS
234验证TLS正常
用户
331用户正常。需要密码
通过
230确定。当前受限目录为/
类型A
200类型现在为ASCII
EPSV
229扩展被动模式OK(| | | | 53360 |)
RETR测试。txt
150接受的数据连接
150 7.3 KB下载

代码如下:

try {

    FTPSClient ftpClient = new FTPSClient("tls",false);

    ftpClient.addProtocolCommandListener(new PrintCommandListener(new  PrintWriter(System.out)));

    ftpClient.connect(host, port);

    int reply = ftpClient.getReplyCode();

    if (FTPReply.isPositiveCompletion(reply)) {
        ftpClient.enterLocalPassiveMode();
        ftpClient.login(username, password);
        ftpClient.enterLocalPassiveMode();
        FileOutputStream outputStream = new FileOutputStream(tempfile);
        ftpClient.setFileType(FTPClient.ASCII_FILE_TYPE);
        ftpClient.retrieveFile("test.txt", outputStream);
        outputStream.close();
        ftpClient.logout();
        ftpClient.disconnect();
    }
} catch (IOException ioe) {
    System.out.println("FTP client received network error");
}

任何想法都非常感谢。

共有3个答案

颛孙正卿
2023-03-14

希望几年后有人觉得我的评论有用。在我的例子中,我将retrieveFile替换为retrieveFileStream。它需要更多的代码,但至少可以工作。

卜瀚漠
2023-03-14

即使以正确的顺序调用了PBSZ 0PROT P,有时服务器确实需要SSL会话重用,而客户端默认情况下并非如此。

例如,当尝试列出目录时,会出现以下回复。因此,不会返回任何内容列表,这样客户端就会看到目录为空:

LIST /
150 Here comes the directory listing.
522 SSL connection failed; session reuse required: see require_ssl_reuse option in sftpd.conf man page

为了克服这一问题,需要通过重写\u prepareDataSocket()方法对FTPSClient进行自定义初始化。

此处详细说明了解决方案:https://eng.wealthfront.com/2016/06/10/connecting-to-an-ftps-server-with-ssl-session-reuse-in-java-7-and-8/

从上述链接获取的工作代码示例:

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Locale;

import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;

import org.apache.commons.net.ftp.FTPSClient;

import com.google.common.base.Throwables;

public class SSLSessionReuseFTPSClient extends FTPSClient {

  // adapted from: https://trac.cyberduck.io/changeset/10760
  @Override
  protected void _prepareDataSocket_(final Socket socket) throws IOException {
    if(socket instanceof SSLSocket) {
      final SSLSession session = ((SSLSocket) _socket_).getSession();
      final SSLSessionContext context = session.getSessionContext();
      try {
        final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
        sessionHostPortCache.setAccessible(true);
        final Object cache = sessionHostPortCache.get(context);
        final Method putMethod = cache.getClass().getDeclaredMethod("put",Object.class, Object.class);
        putMethod.setAccessible(true);
        final Method getHostMethod = socket.getClass().getDeclaredMethod("getHost");
        getHostMethod.setAccessible(true);
        Object host = getHostMethod.invoke(socket);
        final String key = String.format("%s:%s", host, String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT);
        putMethod.invoke(cache, key, session);
      } catch(Exception e) {
        throw Throwables.propagate(e);
      }
    }
  }

}
衡建中
2023-03-14

通常,FTPS连接的FTP命令顺序是(根据RFC 4217)AUTH TLSPBSZ 0,然后是USERPASS,等等。因此,您可以尝试:

FTPSClient ftpClient = new FTPSClient("tls",false);
ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
ftpClient.connect(host, port);
int reply = ftpClient.getReplyCode();
if (FTPReply.isPositiveCompletion(reply)) {
    ftpClient.execPBSZ(0);
    reply = ftpClient.getReplyCode();
    // Check for PBSZ error responses...
    ftpClient.execPROT("P");
    reply = ftpClient.getReplyCode();
    // Check for PROT error responses...

    ftpClient.enterLocalPassiveMode();

这明确地告诉服务器不要缓冲数据连接(PBSZ 0),并使用TLS保护数据传输(PROT P)。

您能够传输一些字节的事实表明,该问题不是防火墙/路由器/NAT的常见复杂性,这是另一个常见的FTPS问题。

希望这能有所帮助!

 类似资料:
  • 我目前正在创建一个基于此小提琴的动态下拉列表 除了我试图调用JSON文件之外,我一直在跟进。我的代码如下: ]; 范围metro可以工作,但是当连接到JSON文件时,其余的就不能工作了。我假设它会工作,因为它实际上是相同的结构。我做错了什么? [编辑] 正如你们中的一些人所回答的那样,在我进行上述操作之前,我最初尝试了这种http注入: 这不起作用,所以我试了另一种方法。所以我假设它与JSON赋值

  • A Freudian slip is when you say one thing, but mean your mother. — Anon 我们每个人都会犯错误,这就是为什么通常铅笔上会配有橡皮擦的原因。 每当 Puppet 客户端在改变一个文件时,就会将改变前的版本做个备份。 如果在 Puppet 客户端上对一个已经存在的文件做修改,不管多小的改变, 我们都可以看到这一过程: # puppe

  • 使用Apache Commons FTPSClient,下载的文件始终存储为0字节。我尝试了不同的方法,但在存储的文件中总是得到0字节。在下面的代码中,我展示了这三种方法。 以下是使用的代码:

  • 问题内容: 我有一个第三方表单解决方案,可以通过导入javascript文件将其嵌入到我的网站中。嵌入脚本的说明实际上与“复制并粘贴以下内容”类似: 看一下实际的javascript文件,它基本上只是一组 现在,我尝试了几件事…我有一个带有模板URL的指令,该指令命中包含该脚本的简单部分。看起来像这样: 指示: form.html 发生的一切只是呈现了html,但脚本的内容却没有… 我尝试了一个请

  • 我想从图中所示的.jar文件中检索compare.ecore模型。 我试图在Eclipse IDE中复制并粘贴它,但没有成功。我用WinRAR打开了给定路径中的.jar文件,但在归档中找不到模型。 如何检索此模型?

  • 我使用Apache IO FTPSClient在FTPS服务器上放置文档时遇到问题。我能够连接到服务器。我的状态很好(返回211)。如果我要求一个目录列表,我得到空。 我没有看到任何错误。我可以通过FileZilla连接到服务器。它在TLS上使用显式FTP。 感谢任何帮助。